2018年东北农业大学春季校赛 题解
【题目链接】
写在前面:从都到尾做了一下这场比赛,似乎好题都是原题,水题都是他们学校自己出的。原题在抄过来的过程中,很多题目的题面、数据范围都出了问题,还有题目数据很水。建议以后这样的比赛不要挂到外面来了,不然别人会骂你们学校不负责任的... ...
A - wyh的曲线
吐槽:
1. 牛客网题面上输入顺序写错了,明明是按 k,a,b 的顺序输入,题面上缺写了以 a,b,k 的顺序输入。
2. 数据很水,我用精确度非常低的方法能水过去
3. 建议将代码提交到原题上进行测评:HDU 4498
精确第很低的方法牛客网上水过:
#include <bits/stdc++.h> using namespace std; const double eps = 1e-8; const int maxn = 1e5 + 10; const int INF = 0x7FFFFFFF; int n; double k[maxn], a[maxn], b[maxn]; double f(double x) { double res = 100.0; for(int i = 1; i <= n; i ++) { res = min(res, 1.0 * k[i] * (x - a[i]) * (x - a[i]) + 1.0 * b[i]); } return res; } double dis(double x1, double y1, double x2, double y2) { return sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2)); } double cal(double L, double R) { return dis(L, f(L), R, f(R)); } double work(double L, double R) { // printf("[%.2f, %.2f]\n", L, R); double mid = (L + R) / 2; if(R - L > 0.005) { return work(L, mid) + work(mid, R); } double s0 = cal(L, mid); double s1 = cal(mid, R); double s2 = cal(L, R); if(fabs(s0 + s1 - s2) < eps) return s0 + s1; return work(L, mid) + work(mid, R); } int main() { // freopen("test.in", "r", stdin); scanf("%d", &n); for(int i = 1; i <= n; i ++) { scanf("%lf%lf%lf", &k[i], &a[i], &b[i]); } printf("%.2f\n", work(0.0, 100.0)); return 0; }
正解:求出所有抛物线之间的交点,相邻两个交点之间必然有一条曲线需要统计到答案中去,设抛物线方程为 $f(x)$,那么 $[L, R]$ 的曲线长度为 $\int _{ L }^{ R }{ \sqrt { { f^{ ' }\left( x \right) }^{ 2 }+1 } dx } $。利用自适应 simpson 积分公式加上分治即可。
#include <bits/stdc++.h> using namespace std; const double eps = 1e-8; const int maxn = 1e5 + 10; const int INF = 0x7FFFFFFF; int n; double k[maxn], a[maxn], b[maxn]; vector<double> vec; double f(double x) { double res = 100.0; for(int i = 1; i <= n; i ++) { res = min(res, k[i] * (x - a[i]) * (x - a[i]) + b[i]); } return res; } void h(int x, int y) { double ta = (k[x]) - (k[y]); double tb = (-k[x] * a[x] * 2.0) - (-k[y] * a[y] * 2.0); double tc = (k[x] * a[x] * a[x] + b[x]) - (k[y] * a[y] * a[y] + b[y]); double delta = tb * tb - 4.0 * ta * tc; if(delta < 0) return; double x1 = (-tb - sqrt(delta)) / (2.0 * ta); double x2 = (-tb + sqrt(delta)) / (2.0 * ta); if(x1 >= 0.0 && x1 <= 100.0) vec.push_back(x1); if(x2 >= 0.0 && x2 <= 100.0) vec.push_back(x2); // printf("%f %f\n", x1, x2); } double G(double x, int idx) { double tmp = 2.0 * k[idx] * x - 2 * a[idx] * k[idx]; return sqrt(tmp * tmp + 1.0); } double cal(double L, double R, int idx) { double res = 0.0; res = (R - L) / 6.0 * (G(L, idx) + 4.0 * G((L + R) / 2.0, idx) + G(R, idx)); return res; } double work(double L, double R, int idx) { double mid = (L + R) /2; double s0 = cal(L, mid, idx); double s1 = cal(mid, R, idx); double s2 = cal(L, R, idx); if(fabs(s0 + s1 - s2) < eps) return s0 + s1; return work(L, mid, idx) + work(mid, R, idx); } int main() { scanf("%d", &n); for(int i = 1; i <= n; i ++) { scanf("%lf%lf%lf", &k[i], &a[i], &b[i]); } b[0] = 100.0; n ++; vec.clear(); vec.push_back(0.0); vec.push_back(100.0); for(int i = 0; i < n; i ++) { for(int j = i + 1; j < n; j ++) { h(i, j); } } sort(vec.begin(), vec.end()); for(int i = 0; i < vec.size(); i ++) { // printf("%d : %f\n", i, vec[i]); } double ans = 0.0; for(int i = 1; i < vec.size(); i ++) { double L = vec[i - 1]; double R = vec[i]; double mid = (L + R) / 2; int idx = 0; double Min = 100.0; for(int j = 0; j < n; j ++) { if(k[j] * (a[j] - mid) * (a[j] - mid) + b[j] < Min) { Min = k[j] * (a[j] - mid) * (a[j] - mid) + b[j]; idx = j; } } // printf("[%lf, %lf], %d ", L, R, idx); // printf(" len : %lf\n", work(L, R, idx)); ans = ans + work(L, R, idx); } printf("%.2f\n", ans); return 0; }
B - wyh的矩阵
手算一下前几项就能找到规律了,答案是一个数的平方,那个数有规律。
#include <bits/stdc++.h> using namespace std; long long a[100010]; void init() { a[3] = 5; long long cha = 8; for(int i = 5; i <= 10000; i = i + 2) { a[i] = a[i-2] +cha; cha = cha + 4; } } int main() { init(); int T; int n; scanf("%d", &T); while(T--) { scanf("%d", &n); printf("%lld\n", a[n]*a[n]); } return 0; }
C - wyh的商机
吐槽:牛客网数据有点水,建议提交到原题 POJ 3728 进行测评
从 $u$ 走到 $v$ 的最大收益分三种情况:
1. $[u, lca(u,v)]$ 进行买卖
2. $[lca(u,v), v]$ 进行买卖
3. $[u, lca(u,v)]$ 进行买,$[lca(u,v), v]$ 进行卖
倍增预处理从 $i$ 节点,往上走 $2^j$ 步的最大值,最小值,最大收益,倒着走下来的最大收益四个值就可以进行询问了。
#include <cstdio> #include <cmath> #include <iostream> #include <algorithm> #include <string> #include <vector> #include <set> #include <map> #include <queue> #include <stack> #include <cstring> using namespace std; const int maxn = 1e5 + 10; const int INF = 0x7FFFFFFF; int n, w[maxn]; int h[maxn], nx[maxn], to[maxn]; int sz; int f[maxn][20]; int Min[maxn][20]; int Max[maxn][20]; int Up[maxn][20]; int Down[maxn][20]; int dep[maxn], vis[maxn]; void add(int x, int y) { to[sz] = y; nx[sz] = h[x]; h[x] = sz ++; } void dfs(int x,int fa) { vis[x] = 1; if(fa == -1) dep[x] = 1; else dep[x] = dep[fa] + 1; f[x][0] = x; f[x][1] = fa; for(int i = 2; i < 18; i ++) { f[x][i] = -1; if((1 << i) <= dep[x]) { f[x][i] = f[f[f[x][i - 1]][1]][i - 1]; } } Min[x][0] = w[x]; Max[x][0] = w[x]; Up[x][0] = 0; Down[x][0] = 0; for(int i = 1; i < 18; i ++) { if((1 << i) > dep[x]) continue; Min[x][i] = min(Min[x][i - 1], Min[f[f[x][i - 1]][1]][i - 1]); Max[x][i] = max(Max[x][i - 1], Max[f[f[x][i - 1]][1]][i - 1]); Up[x][i] = max(max(Up[x][i - 1], Up[f[f[x][i - 1]][1]][i - 1]), Max[x][i - 1] - Min[f[f[x][i - 1]][1]][i - 1]); Down[x][i] = max(max(Down[x][i - 1], Down[f[f[x][i - 1]][1]][i - 1]), Max[f[f[x][i - 1]][1]][i - 1] - Min[x][i - 1]); } for(int i = h[x]; i != -1; i = nx[i]) { if(vis[to[i]]) continue; dfs(to[i], x); } } int LCA(int x, int y) { if(dep[x] < dep[y]) { swap(x, y); } int pre = 17; while(dep[x] != dep[y]) { for(int j = pre; j >= 0; j --) { if(f[x][j] == -1) continue; if(dep[f[x][j]] < dep[y]) continue; x = f[x][j]; pre = j; break; } } if(x == y) return x; pre = 17; while(f[x][1] != f[y][1]) { for(int j = pre; j >= 0; j --) { if(f[x][j] == f[y][j]) continue; x = f[x][j]; y = f[y][j]; pre = j; break; } } x = f[x][1]; return x; } int GetMax(int x, int y) { int res = w[x]; int pre = 17; while(x != y) { for(int j = pre; j >= 0; j --) { if(f[x][j] == -1) continue; if(dep[f[x][j]] < dep[y]) continue; res = max(res, Max[x][j]); x = f[x][j]; pre = j; break; } } return res; } int GetMin(int x, int y) { int res = w[x]; int pre = 17; while(x != y) { for(int j = pre; j >= 0; j --) { if(f[x][j] == -1) continue; if(dep[f[x][j]] < dep[y]) continue; res = min(res, Min[x][j]); x = f[x][j]; pre = j; break; } } return res; } int GetMaxUp(int x, int y) { if(x == y) return 0; int res = 0; for(int j = 17; j >= 0; j --) { if(f[x][j] == -1) continue; if(dep[f[x][j]] < dep[y]) continue; if(dep[f[x][j]] == dep[y]) return Up[x][j]; res = max(Up[x][j], GetMaxUp(f[f[x][j]][1] ,y)); res = max(res, GetMax(x, f[x][j]) - GetMin(f[f[x][j]][1], y)); break; } return res; } int GetMaxDown(int x, int y) { if(x == y) return 0; int res = 0; for(int j = 17; j >= 0; j --) { if(f[x][j] == -1) continue; if(dep[f[x][j]] < dep[y]) continue; if(dep[f[x][j]] == dep[y]) return Down[x][j]; res = max(Down[x][j], GetMaxDown(f[f[x][j]][1] ,y)); res = max(res, GetMax(f[f[x][j]][1], y) - GetMin(x, f[x][j])); break; } return res; } int main() { // freopen("test.in", "r", stdin); scanf("%d", &n); for(int i = 1; i <= n; i ++) { scanf("%d", &w[i]); h[i] = -1; } for(int i = 1; i < n; i ++) { int x, y; scanf("%d%d", &x, &y); add(x, y); add(y, x); } dfs(1, -1); /* for(int i = 1; i <= n; i ++) { printf("Node : %d\n", i); for(int j = 0; j < 30; j ++) { printf("%d to : %d, Min : %d, Max : %d, Up : %d, Down : %d\n", j, f[i][j], Min[i][j], Max[i][j], Up[i][j], Down[i][j]); } } */ int Q; scanf("%d", &Q); while(Q --) { int x, y, lca; scanf("%d%d", &x, &y); /* x -> y */ lca = LCA(x, y); // cout << x << " " << y << ", lca : " << lca << endl; int ans = 0; ans = max(ans, GetMax(y, lca) - GetMin(x, lca)); ans = max(ans, GetMaxDown(x, lca)); ans = max(ans, GetMaxUp(y, lca)); printf("%d\n", ans); } return 0; }
D - wyh的迷宫
BFS 一下就好了。
#include <bits/stdc++.h> using namespace std; int T, n, m; char s[600][600]; int f[600][600]; int sx, sy, ex, ey; int dir[4][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1}, }; int out(int x, int y) { if(x < 0 || x >= n) return 1; if(y < 0 || y >= m) return 1; return 0; } int main() { scanf("%d", &T); while(T--) { memset(f, 0, sizeof f); scanf("%d%d",&n,&m); for(int i = 0; i < n; i ++) { scanf("%s", s[i]); for(int j = 0; j < m; j ++) { if(s[i][j] == 's') sx = i, sy = j; if(s[i][j] == 't') ex = i, ey = j; } } queue<pair<int, int> > q; q.push(make_pair(sx, sy)); f[sx][sy] = 1; while(!q.empty()) { pair<int, int> tp = q.front(); q.pop(); // cout << tp.first << " " << tp.second << endl; for(int i = 0; i < 4; i ++) { int nx = tp.first + dir[i][0]; int ny = tp.second + dir[i][1]; if(out(nx,ny)) continue; if(s[nx][ny] == 'x') continue; if(f[nx][ny]) continue; q.push(make_pair(nx, ny)); f[nx][ny] = 1; } } if(f[ex][ey]) printf("YES\n"); else printf("NO\n"); } return 0; }
E - wyh的阶乘
看 $[1,n]$ 这些数素因子分解后,2 的个数和 5 的个数的较小值,显然 5 比 2 少,只要统计 5 的个数就可以了。
#include <bits/stdc++.h> using namespace std; int T; char s[100010]; int find(int n){ int count= 0; while(n > 0){ count += n / 5; n = n / 5; } return count; } int main() { scanf("%d",&T); while(T--) { long long n; scanf("%lld",&n); printf("%lld\n", find(n)); } return 0; }
F - wyh的集合
两边个数差值越少乘积越大。
#include <bits/stdc++.h> using namespace std; int main() { int T; long long n; scanf("%d", &T); while(T--) { scanf("%lld", &n); if(n == 0 || n == 1) { printf("%d\n", 0); } else { long long x = n/2; long long y = n-n/2; printf("%lld\n", x* y); } } return 0; }
G - wyh的考核
考虑每个人对答案做出的贡献,每个人对答案都贡献都是一样的。
假设 $n$ 个人总共打了 $s$ 分,平均值 $ave = \frac { s }{ n } $,我们只要让一个人打平均分,然后去看剩下的 $n-1$ 个人打 $s - ave$ 分有几种方案,这个可以 $dp$ 得到。
#include <bits/stdc++.h> using namespace std; const int mod = 1000000007; const int maxn = 1e5 + 10; const int INF = 0x7FFFFFFF; int T; int n, m; int f[70][13000]; int sum[13000]; int GetPos(int x) { if(x < 0) return 0; return sum[x]; } int Get(int L, int R) { // cout << L << " " << R << endl; return (GetPos(R) - GetPos(L - 1) + mod) % mod; } void init() { memset(f, 0, sizeof f); f[0][0] = 1; for(int i = 0; i <= 12000; i ++) { sum[i] = 1; } for(int i = 1; i <= n; i ++) { for(int j = 0; j <= i * m; j ++) { f[i][j] = Get(j - min(m, j), j); /* for(int k = 0; k <= min(m, j); k ++) { f[i][j] = (f[i][j] + f[i - 1][j - k]) % mod; } */ } sum[0] = f[i][0]; for(int j = 1; j <= 12000; j ++) { sum[j] = (sum[j - 1] + f[i][j]) % mod; } } } int main() { //freopen("test.in", "r", stdin); scanf("%d", &T); while(T --) { scanf("%d%d", &n, &m); init(); int ans = 0; for(int s = 0; s <= n * m; s ++) { if(s % n) continue; int ave = s / n; long long tmp = 1LL * f[n - 1][s - ave] * n % mod; ans = (ans + tmp) % mod; } printf("%d\n", ans); } return 0; }
H - wyh的吃鸡
主要注意安全区域是一个连通块即可,并非一个格子,有可能是一群格子。
#include <bits/stdc++.h> using namespace std; const int maxn = 1010; const int INF = 0x7FFFFFFF; char s[maxn][maxn]; int n, k; int sx, sy; int ex, ey; int dis[maxn][maxn][2]; int f[maxn][maxn][2]; int dir[4][2] = { {1, 0}, {-1, 0}, {0, 1}, {0, -1} }; int out(int x, int y) { if(x < 0 || x >= n) return 1; if(y < 0 || y >= n) return 1; return 0; } int main() { int T; scanf("%d", &T); while(T--) { scanf("%d%d", &n, &k); for(int i = 0; i < n; i ++) { scanf("%s", s[i]); } if(n > 100) while(1) {} int sum = 0; sx = sy = ex = ey = -1; for(int i = 0; i < n; i ++) { for(int j = 0; j < n; j ++) { if(s[i][j] == 'S') sx = i, sy = j; if(s[i][j] == 'X') sum++, ex = i, ey = j; dis[i][j][0] = dis[i][j][1] = INF; } } // if(sum != 1) while(1) {} if(sx == -1 || sy == -1 || ex == -1 || ey == -1){ while(1) {} } queue<int> qx; queue<int> qy; queue<int> qc; qx.push(sx); qy.push(sy); qc.push(0); memset(f, 0, sizeof f); dis[sx][sy][0] = 0; f[sx][sy][0] = 1; while(!qx.empty()) { int nx = qx.front(); int ny = qy.front(); int nc = qc.front(); qx.pop(); qy.pop(); qc.pop(); // cout << nx<<" " << ny << " " <<nc<<endl; f[nx][ny][nc] = 0; for(int i = 0; i < 4; i ++) { int tx = nx + dir[i][0]; int ty = ny + dir[i][1]; int tc = nc; if(out(tx, ty)) continue; if(s[tx][ty] == 'O') continue; if(s[tx][ty] == 'C') tc = 1; // cout << tx<<" " << ty << " " <<tc<<endl; int cost; if(nc == 0) cost = 2; else cost = 1; if(dis[nx][ny][nc] + cost < dis[tx][ty][tc]) { dis[tx][ty][tc] = dis[nx][ny][nc] + cost; if(f[tx][ty][tc] == 0) { f[tx][ty][tc] = 1; qx.push(tx); qy.push(ty); qc.push(tc); } } } } int ans = INF; for(int i = 0; i < n; i ++) { for(int j = 0; j < n; j ++) { if(s[i][j] == 'X') { ans = min(ans, dis[i][j][0]); ans = min(ans, dis[i][j][1]); } } } if(ans > k) { printf("NO\n"); } else { printf("YES\n"); printf("%d\n", ans); } } return 0; } /* 1 10 100 .......... .......... .......X.. .......... .......... .......... .......... ..S....... .......... .......... */
I - wyh的物品
经典的 01 分数规划。首先有一个单调性,比例越小越可能构造出来,比例越大越不可能构造出来,外面只要验证大于等于 $x$ 的比例能不能构造出来,如果可以,答案会更大,否则答案会更小,因此可以二分 $x$,然后进行验证。
验证 $\frac { \sum { b } }{ \sum { a } } \ge x $ 是否可行,等价于验证 $\sum { b } -x\sum { a } \ge 0$ 是否可行。另 ${ c }_{ i } = { b }_{ i }-x*{ a }_{ i }$,只要取最大的 $k$ 个 $c$,看 $sum$ 是否大于等于 0 即可。
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 10; const int INF = 0x7FFFFFFF; int T, n, k; double a[maxn], b[maxn], c[maxn]; int check(double x) { for(int i = 1; i <= n; i ++) { c[i] = b[i] - x * a[i]; } sort(c + 1, c + 1 + n); double sum = 0.0; for(int i = n; i >= n - k + 1; i --) { sum = sum + c[i]; } if(sum >= 0) return 1; return 0; } int main() { // freopen("test.in", "r", stdin); scanf("%d", &T); while(T --) { scanf("%d%d", &n, &k); for(int i = 1; i <= n; i ++) { scanf("%lf%lf", &a[i], &b[i]); } double L = 0, R = 1e18, ans; for(int it = 1; it <= 100; it ++) { double mid = (L + R) / 2; if(check(mid)) { ans = mid; L = mid; } else { R = mid; } } printf("%.2f\n", ans); } return 0; }
J - wyh的问题
吐槽:牛客网上数据错了,我多次和出题人说,他不信。建议提交到原题进行测评:NYOJ 304
如果数据没有错,下面这个代码怎么会超时?感觉出(chao)题人很逗啊... ...
#include <bits/stdc++.h> using namespace std; const long long limit = 1e9; const long long INF = limit * limit; struct X { int id; long long d, w; }s[1010]; int n; int id; bool cmp(const X&a, const X&b) { return a.d < b.d; } long long dp[1010][1010][2]; long long sum[1010]; long long cal(int x1, int y1, int x2, int y2) { return sum[y1] - sum[x1 - 1] - (sum[y2] - sum[x2 - 1]); } int main() { while(~scanf("%d%d", &n, &id)) { for(int i = 1; i <= n; i ++) { scanf("%lld%lld", &s[i].d, &s[i].w); sum[i] = sum[i - 1] + s[i].w; s[i].id = i; if(i > 1 && s[i].d < s[i-1].d) while(1) {} } } return 0; }
正解:
可以观察到如果他从起点出发关了某盏灯,那么途径的灯都会被关掉,也就是从起点往两边跑来跑去关灯的过程,很明显是个区间 dp,记录一下关完某个区间的灯,在左端点还有右端点的最小耗电量即可。
#include <bits/stdc++.h> using namespace std; const long long limit = 1e9; const long long INF = limit * limit; struct X { int id; long long d, w; }s[1010]; int n; int id; bool cmp(const X&a, const X&b) { return a.d < b.d; } long long dp[1010][1010][2]; long long sum[1010]; long long cal(int x1, int y1, int x2, int y2) { return sum[y1] - sum[x1 - 1] - (sum[y2] - sum[x2 - 1]); } int main() { while(~scanf("%d%d", &n, &id)) { for(int i = 1; i <= n; i ++) { scanf("%lld%lld", &s[i].d, &s[i].w); sum[i] = sum[i - 1] + s[i].w; s[i].id = i; } for(int i = 1; i <= n; i ++) { for(int j = i; j <= n; j ++) { dp[i][j][0] = INF; dp[i][j][1] = INF; } } dp[id][id][0] = dp[id][id][1] = 0; for(int len = 2; len <= n; len ++) { for(int L = 1; L <= n; L ++) { int R = L + len - 1; if(R > n) break; // cal [L][R][0] // [L, R - 1][0] if(dp[L][R - 1][0] != INF) dp[L][R][0] = min(dp[L][R][0], dp[L][R - 1][0] + (s[R].d - s[L].d) * cal(1, n, L, R - 1) + (s[R].d - s[L].d) * cal(1, n, L, R)); // [L, R - 1][1] if(dp[L][R - 1][1] != INF) dp[L][R][0] = min(dp[L][R][0], dp[L][R - 1][1] + (s[R].d - s[R - 1].d) * cal(1, n, L, R - 1) + (s[R].d - s[L].d) * cal(1, n, L, R)); // [L + 1, R][0] if(dp[L + 1][R][0] != INF) dp[L][R][0] = min(dp[L][R][0], dp[L + 1][R][0] + (s[L + 1].d - s[L].d) * cal(1, n, L + 1, R)); // [L + 1, R][1] if(dp[L + 1][R][1] != INF) dp[L][R][0] = min(dp[L][R][0], dp[L + 1][R][1] + (s[R].d - s[L].d) * cal(1, n, L + 1, R)); // cal [L][R][1] // [L, R - 1][0] if(dp[L][R - 1][0] != INF) dp[L][R][1] = min(dp[L][R][1], dp[L][R - 1][0] + (s[R].d - s[L].d) * cal(1, n, L, R - 1)); // [L, R - 1][1] if(dp[L][R - 1][1] != INF) dp[L][R][1] = min(dp[L][R][1], dp[L][R - 1][1] + (s[R].d - s[R - 1].d) * cal(1, n, L, R - 1)); // [L + 1, R][0] if(dp[L + 1][R][0] != INF) dp[L][R][1] = min(dp[L][R][1], dp[L + 1][R][0] + (s[L + 1].d - s[L].d) * cal(1, n, L + 1, R) + (s[R].d - s[L].d) * cal(1, n, L, R)); // [L + 1, R][1] if(dp[L + 1][R][1] != INF) dp[L][R][1] = min(dp[L][R][1], dp[L + 1][R][1] + (s[R].d - s[L].d) * cal(1, n, L + 1, R) + (s[R].d - s[L].d) * cal(1, n, L, R)); } } printf("%lld\n", min(dp[1][n][0], dp[1][n][1])); } return 0; }
K - wyh的数列
去寻找 $f_i=0$, $f_{i+1}=1$的除 0 之外的最小 $i$,找到了这个就找到了循环节。
#include <bits/stdc++.h> using namespace std; unsigned long long f[5000]; unsigned long long a, b; unsigned long long c; unsigned long long qpow(unsigned long long a, unsigned long long b, unsigned long long mod) { unsigned long long res = 1; a = a % mod; while(b) { if(b % 2 == 1) { res = (res * a) % mod; } a = (a * a) % mod; b = b / 2; } return res; } int main() { int T; scanf("%d", &T); while(T--) { cin >> a >> b >> c; f[0] = 0; f[1] = 1; unsigned long long limit; for(int i = 2; ; i ++) { f[i] = (f[i-1]+ f[i-2]) % c; if(f[i] == 1 && f[i-1] == 0) { limit = i; break; } } //[0, limit - 2] cout << f[qpow(a, b, limit - 1)] << endl; } return 0; } /* 3 1 1 2 2 3 1000 32122142412412142 124124124412124 123 */
L - wyh的天鹅
吐槽:打开题目,看到萌值没有数据范围,问了一下出(chao)题人,说是在 $[1, 10^5]$,然后我开始写,写完提交,返回错误,看了好久代码,看不出毛病,然后我就在想可能优秀的出(chao)题人告诉我的数据范围是骗我的,因此我扩大到了 $10^6$,提交返回正确。CNMLGB ?后来出题人在题面上 update 了数据范围:$[1,1000000000]$,再一次骗我?我开到 $10^6$ 是怎么过的?
题解:经典的权值线段树,直接在线段树上选择往右走还是往左走就可以了。
#include <bits/stdc++.h> using namespace std; const int maxn = 1e6+10; int T; int s[maxn * 4]; char op[20]; int n, m; int ans; void build(int l, int r, int rt) { s[rt] = 0; if(l == r) return; int mid = (l+r)/2; build(l, mid, 2*rt); build(mid+1, r, 2*rt+1); } void update(int pos, int val, int l, int r, int rt) { if(l == r) { s[rt] += val; return; } int mid = (l+r)/2; if(pos <= mid) update(pos, val, l, mid, 2 * rt); else update(pos, val, mid+1, r, 2*rt+1); s[rt] = s[2*rt]+s[2*rt+1]; } void query(int k, int l, int r, int rt) { if(l == r) { ans = l; return; } int mid = (l+r)/2; if(s[2*rt+1] >= k) query(k,mid+1,r,2*rt+1); else query(k - s[2*rt+1],l,mid,2*rt); } int main() { scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); build(0,1e6,1); for(int i = 1; i <= n; i ++) { int x; scanf("%d",&x); if(x > 1e6) while(1) {} update(x,1,0,1e6,1); } while(m--) { scanf("%s", op); int x; scanf("%d", &x); if(op[0] == 'q') { query(x,0,1e6,1); printf("%d\n", ans); } else if(op[0] == 'i') { if(x > 1e6) while(1) {} update(x, 1, 0, 1e6, 1); } else { if(x > 1e6) while(1) {} update(x, -1, 0, 1e6, 1); } } } return 0; }
M - wyh的数字
水题。
#include <bits/stdc++.h> using namespace std; int T; char s[100010]; int main() { scanf("%d",&T); while(T--) { scanf("%s",s); int ans = 0; for(int i = 0; s[i];i++){ if(s[i] == '7') ans++; } cout << ans <<endl; } return 0; }