第十六届北京师范大学程序设计竞赛决赛(网络同步赛)

coding

题目链接  第十六届北京师范大学程序设计竞赛决赛

一句话总结:迟到选手抢到FB之后进入梦游模式最后因为忘加反向边绝杀失败……

好吧其实还是自己太弱

下面进入正题

Problem A

签到题(读题是一件非常有趣事情)

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b) for (int i(a); i <= (b); ++i)

#define dec(i, a, b) for (int i(a); i >= (b); --i)

#define MP make_pair

#define fi first

#define se second

typedef long long LL;

int main(){

int T; string s;

scanf("%d", &T);

while (T--){

int n;

scanf("%d", &n);

int fg = 1;

rep(i, 1, n){

cin >> s;

if (s != "PERFECT") fg = 0;

}

puts(fg ? "MILLION Master" : "NAIVE Noob");

}

return 0;

}

 

Problem B

设读进来的那个序列为$b_{i}$

要还原出的那个序列答案为$a_{i}$

我们求出$a_{i}$对$b_{i}$每一项的贡献就可以了。

这个过程实现起来不难。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b) for (int i(a); i <= (b); ++i)

#define dec(i, a, b) for (int i(a); i >= (b); --i)

typedef long long LL;

const LL mod = 1e9 + 7;

const int N = 1e3 + 10;

int T;

int n;

LL a[N], b[N], c[N];

LL k;

inline LL Pow(LL a, LL b, LL mod){

LL ret(1);

for (; b; b >>= 1, (a *= a) %= mod) if (b & 1) (ret *= a) %= mod;

return ret;

}

void pre(){

int cnt = 0;

c[++cnt] = 1;

LL now = 1;

rep(i, 1, n - 1){

now = now * (k + i - 1) % mod;

now = now * Pow((LL)i, mod - 2, mod) % mod;

c[++cnt] = now;

}

}

int main(){

scanf("%d", &T);

while (T--){

scanf("%d%lld", &n, &k);

memset(c, 0, sizeof c);

pre();

rep(i, 1, n) scanf("%lld", b + i);

a[1] = b[1];

rep(i, 1, n){

int cnt = 0;

rep(j, i, n){

++cnt;

b[j] -= (c[cnt] * a[i] % mod);

b[j] += mod;

b[j] %= mod;

}

a[i + 1] = b[i + 1];

}

rep(i, 1, n - 1) printf("%lld ", a[i]);

printf("%lld\n", a[n]);

}

return 0;

}

  

 

Problem C

打表之后找规律

#include<bits/stdc++.h>

using namespace std;

int T;

int n;

int main(){

cin >> T;

while (T--){

cin >> n;

cout << fixed << setprecision(10) << (n * n - 1) / 3.0 << endl;

}

return 0;

}

 

Problem D

这个DP转移

每个点有两种转移的方向,每个方向取最近的那个点就好了。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b) for (int i(a); i <= (b); ++i)

#define dec(i, a, b) for (int i(a); i >= (b); --i)

#define MP make_pair

#define fi first

#define se second

typedef long long LL;

const int N = 1e5 + 10;

int T;

int n, m, k;

LL a[N], b[N], c[N], f[N], g[N], h[N];

map <LL, LL> mp;

set <LL> s;

int main(){

scanf("%d", &T);

while (T--){

scanf("%d%d%d", &n, &m, &k);

rep(i, 1, n) scanf("%lld", a + i);

rep(i, 1, m) scanf("%lld", b + i);

rep(i, 1, k) scanf("%lld", c + i);

rep(i, 1, n) f[i] = 1;

rep(i, 1, m) g[i] = 1e15;

mp.clear();

rep(i, 1, n) mp[a[i]] = f[i];

mp[1e18] = 1e18, mp[-1e18] = 1e18;

s.clear();

rep(i, 1, n) s.insert(a[i]);

s.insert(1e18);

s.insert(-1e18);

rep(i, 1, m){

LL xx = b[i];

auto it = s.lower_bound(xx);

g[i] = min(g[i], mp[*it] + abs((*it) - xx) + 1);

--it;

g[i] = min(g[i], mp[*it] + abs((*it) - xx) + 1);

}

rep(i, 1, k) h[i] = 1e15;

mp.clear();

rep(i, 1, m) mp[b[i]] = g[i];

mp[1e18] = 1e18, mp[-1e18] = 1e18;

s.clear();

rep(i, 1, m) s.insert(b[i]);

s.insert(1e18);

s.insert(-1e18);

rep(i, 1, k){

LL xx = c[i];

auto it = s.lower_bound(xx);

h[i] = min(h[i], mp[*it] + abs((*it) - xx) + 1);

--it;

h[i] = min(h[i], mp[*it] + abs((*it) - xx) + 1);

}

LL ans = 1e18;

rep(i, 1, k) ans = min(ans, h[i]);

printf("%lld\n", ans);

}

return 0;

}

 

 

Problem E

考虑到长度为$k$的子序列个数不超过$10^{5}$,那么直接暴力,搜索深度不超过$9$。

注意:$k$比较大的时候考虑反面即可。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b) for (int i(a); i <= (b); ++i)

#define dec(i, a, b) for (int i(a); i >= (b); --i)

#define MP make_pair

#define fi first

#define se second

typedef long long LL;

const int N = 1e5 + 10;

int T;

int n, k;

int z;

int c[N];

LL a[N];

LL ans;

void check(LL x){

LL vv = x * x;

ans ^= vv;

}

void dfs(int x, LL now){

if (x > k){

check(now);

return;

}

else{

rep(i, z, n){

int la = z;

z = i + 1;

dfs(x + 1, now + a[i]);

z = la;

}

}

}

void dfs2(int x, LL now){

if (x > k){

check(now);

return;

}

else{

rep(i, z, n){

int la = z;

z = i + 1;

dfs2(x + 1, now - a[i]);

z = la;

}

}

}

int main(){

scanf("%d", &T);

while (T--){

scanf("%d%d", &n, &k);

LL sum = 0;

rep(i, 1, n) scanf("%lld", a + i), sum += a[i];

z = 1;

ans = 0;

if (k > n - k){

k = n - k;

dfs2(1, sum);

}

else{

dfs(1, 0);

}

printf("%lld\n", ans);

}

return 0;

}

 

 

Problem F

显然答案是单调的。

二分答案,把那些符合条件的汤圆一个个加入队列,然后BFS,到最后如果所有汤圆都被删除了,那么该答案可行。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b) for (int i(a); i <= (b); ++i)

#define dec(i, a, b) for (int i(a); i >= (b); --i)

#define MP make_pair

#define fi first

#define se second

typedef long long LL;

typedef pair <int, LL> PII;

const int N = 1e5 + 10;

int T;

int n, m;

int vis[N], inq[N];

LL a[N], bb[N];

LL l, r;

vector <PII> v[N];

bool check(LL now){

queue <int> q;

memset(vis, 0, sizeof vis);

memset(inq, 0, sizeof inq);

rep(i, 1, n) bb[i] = a[i];

rep(i, 1, n) if (bb[i] <= now) q.push(i), inq[i] = 1;

while (!q.empty()){

int x = q.front();

vis[x] = 1;

q.pop();

inq[x] = 0;

for (auto edge : v[x]){

int u = edge.fi;

LL w = edge.se;

if (vis[u]) continue;

bb[u] -= w;

if (bb[u] <= now){

if (!inq[u]) q.push(u), inq[u] = 1;

}

}

}

rep(i, 1, n) if (!vis[i]) return false;

return true;

}

int main(){

scanf("%d", &T);

while (T--){

scanf("%d%d", &n, &m);

rep(i, 0, n + 1) v[i].clear();

rep(i, 0, n + 1) a[i] = 0;

rep(i, 1, m){

int x, y;

LL z;

scanf("%d%d%lld", &x, &y, &z);

v[x].push_back({y, (LL)z});

v[y].push_back({x, (LL)z});

a[x] += z;

a[y] += z;

}

l = 0, r = 1e14;

while (l + 1 < r){

LL mid = (l + r) / 2ll;

if (check(mid)) r = mid;

else l = mid + 1;

}

if (check(l)) printf("%lld\n", l);

else printf("%lld\n", r);

}

return 0;

}

 

Problem G

模拟题,没什么好说的。(我还是WA了好几发)

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b) for (int i(a); i <= (b); ++i)

#define dec(i, a, b) for (int i(a); i >= (b); --i)

#define MP make_pair

#define fi first

#define se second

typedef long long LL;

char s[24];

bool ff[24];

int T;

bool upper(char c){ return c >= 'A' && c <= 'Z'; }

bool check(int n){

bool re = 1;

bool flag = 0;

int cnt = 0;

if (!upper(s[0])) s[0] += 'A' - 'a', flag = 1;

rep(i, 1, n - 1){

if (upper(s[i]) && upper(s[i - 1])) re = 0;

if (upper(s[i])) cnt++, ff[i] = 1;

}

if (flag) s[0] += 'a' - 'A';

return re && (cnt) && !upper(s[n - 1]);

}

int main(){

cin >> T;

while (T--){

scanf("%s", &s);

memset(ff, 0, sizeof ff);

int n = strlen(s);

if (check(n)){

rep(i, 0, n - 1){

if (ff[i]) putchar('_');

if (upper(s[i])) s[i] += 'a' - 'A';

putchar(s[i]);

}

putchar(10);

}

else puts(s);

}

return 0;

}

Problem H

数据结构题,留坑。

Problem I

每次交换相邻的两个不一样的元素会使整个序列的逆序对数改变$1$

那么计算一下逆序对个数就好了。

#include <bits/stdc++.h>

using namespace std;

#define rep(i, a, b) for (int i(a); i <= (b); ++i)

#define dec(i, a, b) for (int i(a); i >= (b); --i)

#define MP make_pair

#define fi first

#define se second

typedef long long LL;

const int N = 1e6 + 10;

int T;

int n;

int a[N];

char s[N];

LL k;

int main(){

scanf("%d", &T);

while (T--){

scanf("%d%lld", &n, &k);

scanf("%s", s + 1);

rep(i, 1, n) a[i] = (s[i] == 'D');

LL cc = 0;

rep(i, 1, n) cc += a[i];

LL ju = 1ll * cc * (LL)(n - cc);

if (ju < k) {

puts("-1");

continue;

}

LL cnt = 0, ss = 0;

rep(i, 1, n){

if (a[i] == 0) cnt += ss;

ss += a[i];

}

printf("%lld\n", abs(cnt - k));

}

return 0;

}

Problem J

计算几何,留坑。

Problem K

留坑。

以上是 第十六届北京师范大学程序设计竞赛决赛(网络同步赛) 的全部内容, 来源链接: utcz.com/z/509601.html

回到顶部