2024.05 别急记录
1. POI2015 - Podział naszyjnika
考虑对每个位置附一个随机权值,保证序列中所有等于某个数的位置权值异或和为
点击查看代码
//P3587 #include <bits/stdc++.h> using namespace std; typedef long long ll; void solve();int main(){ solve(); return 0; } const int N = 1e6 + 10; int n, k, a[N], cnt, mx; ll xom[N], val[N], ans; unordered_map<ll, int> mp; vector<int> g[N]; int cl(int x, int y){ return min(y - x, x + n - y); } mt19937 rng(time(0)); uniform_int_distribution<long long>gen(1,0x3f3f3f3f3f3f3f3f); void solve(){ srand(unsigned(time(NULL))); mp[0] = ++ cnt; g[mp[0]].push_back(0); scanf("%d%d", &n, &k); for(int i = 1; i <= n; ++ i){ scanf("%d", &a[i]); val[i] = gen(rng); xom[a[i]] ^= val[i]; } for(int i = 1; i <= n; ++ i){ val[i] ^= xom[a[i]]; xom[a[i]] = 0; val[i] ^= val[i-1]; if(!mp[val[i]]){ mp[val[i]] = ++ cnt; } g[mp[val[i]]].push_back(i); } for(int i = 1; i <= cnt; ++ i){ int x = g[i].size(); if(mp[val[n]] == i){ -- x; } ans += (ll)x * (x-1) / 2; int pr = 0; for(int j = 1; j < x; ++ j){ while(pr < j && cl(g[i][pr], g[i][j]) < cl(g[i][pr+1], g[i][j])){ ++ pr; } mx = max(mx, cl(g[i][pr], g[i][j])); } } printf("%lld %d", ans, n - mx - mx); }
2. XJTUPC2024 - 循环移位
三种运算做法本质相同,考虑异或的做法。
预处理
观察到只有
考虑递推
求好
复杂度
点击查看代码
//P10524 #include <bits/stdc++.h> using namespace std; typedef long long ll; void solve();int main(){ solve(); return 0; } const int N = (1 << 20) + 10; int n, m, a[N]; ll sum[N][20]; int clc(int p, int q, int k, int op){ p += m; if(op == 0){ return ((p>>k)&1) ^ ((q>>k)&1); } else if(op == 1){ return ((p>>k)&1) & ((q>>k)&1); } else { return ((p>>k)&1) | ((q>>k)&1); } } ll calc(int op){ memset(sum, 0, sizeof(sum)); for(int j = 0; j < n; ++ j){ for(int i = 0; i < m; ++ i){ sum[0][j] += clc(i, a[i], j, op); } for(int i = 1; i < (1 << j + 1); ++ i){ sum[i][j] = sum[i-1][j]; for(int k = (i-1) % (1<<j); k < m; k += (1 << j)){ sum[i][j] -= clc(k-i+1, a[k], j, op); sum[i][j] += clc(k-i, a[k], j, op); } } } ll ans = 0; for(int i = 0; i < m; ++ i){ ll now = 0; for(int j = 0; j < n; ++ j){ now += sum[i%(1<<j+1)][j] * (1 << j); } ans = max(ans, now); } return ans; } void solve(){ scanf("%d", &n); m = 1 << n; for(int i = 0; i < m; ++ i){ scanf("%d", &a[i]); } printf("%lld %lld %lld\n", calc(0), calc(1), calc(2)); }
3. XJTUPC2024 - 最后一块石头的重量
题目等价于求操作后
可以使用随一个排列然后小范围背包过,也可以使用厉害科技。
点击查看代码
//P10527 #include <bits/stdc++.h> using namespace std; typedef long long ll; void solve();int main(){ solve(); return 0; } const int N = 1e4 + 10; int n, x, a[N]; int f[N*2], g[N*2]; void solve(){ scanf("%d", &n); int sum = 0, all = 0, ss = 0; for(int i = 1; i <= n; ++ i){ scanf("%d", &a[i]); sum += a[i]; all += a[i]; x = max(x, a[i]); } ss = sum; sum /= 2; int b = 0, w = 0; while(w + a[b+1] <= sum){ ++ b; w += a[b]; } f[w-sum+x] = b + 1; for(int i = b + 1; i <= n; ++ i){ memcpy(g, f, sizeof(g)); for(int j = x; j; -- j){ f[j+a[i]] = max(f[j+a[i]], g[j]); } for(int j = x + x; j >= x + 1; -- j){ for(int k = f[j]-1; k >= max(1, g[j]); -- k){ f[j-a[k]] = max(f[j-a[k]], k); } } } int ans = 0; for(int j = x; j; -- j){ if(f[j]){ ans = all - sum - j + x; break; } } printf("%d\n", ans + ans - ss); }
4. [ARC176D] Swap Permutation
首先有
问题转化为给定
考虑一个位置
对于不同的
所以可以做到
点击查看代码
//AT_arc176_d #include <bits/stdc++.h> using namespace std; typedef long long ll; void solve();int main(){ solve(); return 0; } const int N = 2e5 + 10; const int mp[3][3] = {{0,1,4},{2,3,4},{4,4,4}}; int n, m, p[N], pos[N], a[N], cnt[5]; const ll P = 998244353; ll ans; struct mat{ ll a[4][4]; }; mat mul(mat x, mat y){ mat z; memset(z.a, 0, sizeof(z.a)); for(int k = 0; k < 4; ++ k){ for(int i = 0; i < 4; ++ i){ for(int j = 0; j < 4; ++ j){ z.a[i][j] += x.a[i][k] * y.a[k][j] % P; if(z.a[i][j] >= P){ z.a[i][j] -= P; } } } } return z; } mat qp(mat x, int y){ mat ans = x; -- y; while(y){ if(y & 1){ ans = mul(ans, x); } x = mul(x, x); y >>= 1; } return ans; } void solve(){ scanf("%d%d", &n, &m); for(int i = 1; i <= n; ++ i){ scanf("%d", &p[i]); pos[p[i]] = i; } a[0] = a[n+1] = 2; cnt[mp[0][0]] = n-1; for(int i = 1; i <= n; ++ i){//i 1, n-i 0 int j = pos[i]; -- cnt[mp[a[j-1]][a[j]]]; -- cnt[mp[a[j]][a[j+1]]]; a[j] = 1; ++ cnt[mp[a[j-1]][a[j]]]; ++ cnt[mp[a[j]][a[j+1]]]; mat k; k.a[0][0] = (ll)n * (n-1) / 2 - 2 * i; k.a[0][1] = i; k.a[0][2] = i; k.a[0][3] = 0; k.a[1][0] = n-i-1; k.a[1][1] = (ll)n * (n-1) / 2 - (n-1); k.a[1][2] = 1; k.a[1][3] = i-1; k.a[2][0] = n-i-1; k.a[2][1] = 1; k.a[2][2] = (ll)n * (n-1) / 2 - (n-1); k.a[2][3] = i-1; k.a[3][0] = 0; k.a[3][1] = n-i; k.a[3][2] = n-i; k.a[3][3] = (ll)n * (n-1) / 2 - 2 * (n-i); for(int j = 0; j < 4; ++ j){ for(int q = 0; q < 4; ++ q){ k.a[j][q] %= P; } } k = qp(k, m); ans += (ll)cnt[0] * (k.a[0][1] + k.a[0][2]) % P; ans += (ll)cnt[1] * (k.a[1][1] + k.a[1][2]) % P; ans += (ll)cnt[2] * (k.a[2][1] + k.a[2][2]) % P; ans += (ll)cnt[3] * (k.a[3][1] + k.a[3][2]) % P; ans %= P; } printf("%lld\n", ans); }
5. APIO2024 - September
观察到一个位置
- 对于
, 组成的集合相同。 - 树去除掉这个集合内的点后仍然连通。
第一个限制很好做,第二个限制可以给每个点打上需要删除的标记,删除一个点时把需要删除的标记设为
点击查看代码
//qoj8724 #include <bits/stdc++.h> using namespace std; typedef long long ll; int val[100010], del[100010], nd[100010]; vector<int> g[100010]; int solve(int N, int M, std::vector<int> F, std::vector<std::vector<int>> S){ int cnt = 0, ndc = 0; ll sum = 0; int n = N, m = M; for(int i = 1; i < n; ++ i){ g[F[i]].push_back(i); } for(int i = 0; i < n - 1; ++ i){ for(int j = 0; j < m; ++ j){ sum -= abs(val[S[j][i]]); if(!j){ int p = S[j][i]; val[p] += m-1; if(nd[p]){ nd[p] = 0; -- ndc; } del[p] = 1; for(int q : g[p]){ if(!del[q]){ nd[q] = 1; ++ ndc; } } } else { -- val[S[j][i]]; } sum += abs(val[S[j][i]]); if(sum == 0 && ndc == 0){ ++ cnt; } } } for(int i = 0; i <= n; ++ i){ vector<int> ().swap(g[i]); val[i] = nd[i] = del[i] = 0; } return cnt; } //int main(){ // printf("%d\n", solve(3, 1, {-1, 0, 0}, {{1, 2}})); // printf("%d\n", solve(5, 2, {-1, 0, 0, 1, 1}, {{1, 2, 3, 4}, {4, 1, 2, 3}})); // return 0; //}
6. LuoguP3791 - 普通数学题
设
其中
那么设一个块为
问题转化为给定区间求约数个数和,转化为给定前缀求约数个数和,数论分块即可。
复杂度
点击查看代码
//P3791 #include <bits/stdc++.h> using namespace std; typedef long long ll; void solve();int main(){ solve(); return 0; } const ll P = 998244353; ll n, m, x, ans; map<ll, ll> mp; ll cw(ll v){ if(v <= 0 || mp[v]){ return mp[v]; } ll ans = 0; for(ll i = 1, j = 0; i <= v; i = j + 1){ j = v / (v / i); ans += v / i * (j - i + 1); } return mp[v] = ans; } ll cq(ll v, int p){ return (cw(v + (1ll<<p) - 1) - cw(v - 1) + P) % P; } void solve(){ cin >> n >> m >> x; ++ n; ++ m; for(int i = 0; i <= 40; ++ i){ if(n & (1ll << i)){ for(int j = 0; j <= 40; ++ j){ if(m & (1ll << j)){ ll t = x ^ n ^ m; int r = max(i, j); t ^= (1ll << i) ^ (1ll << j); t = (t | ((1ll<<r)-1)) - (1ll<<r) + 1; ans += cq(t, r) * (1ll << min(i, j)) % P; ans %= P; } } } } printf("%lld\n", ans); }
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步