ABC365(D,E)
- 石头剪刀布,给出对手的出招,问在保证不败的情况下最多能赢多少回
- 记 表示第 局出石头/剪刀/布 , 累计最多赢了多少回回, 直接转移即可
#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l);i<=r;++i)
#define G(i,r,l) for(int i(r);i>=l;--i)
using namespace std;
using ll = long long;
const int N = 5e5 + 105;
const int inf = 0x3f3f3f3f;
int n;
int f[N][5],g[N];
char s[N];
signed main(){
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin>>n>>s;
F(i,0,n-1){
if(s[i] == 'R') g[i + 1] = 0;
else if(s[i] == 'S') g[i + 1] = 1;
else if(s[i] == 'P') g[i + 1] = 2;
}
F(i,1,n) f[i][0] = f[i][1] = f[i][2] = -inf;
F(i,1,n){
if(g[i] == 0){
f[i][2] = max( f[i-1][0] , f[i-1][1] ) + 1;
f[i][0] = max( f[i-1][2] , f[i-1][1] );
}
else if(g[i] == 1){
f[i][0] = max( f[i-1][1] , f[i-1][2] ) + 1;
f[i][1] = max( f[i-1][0] , f[i-1][2] );
}
else if(g[i] == 2){
f[i][1] = max( f[i-1][0] , f[i-1][2] ) + 1;
f[i][2] = max( f[i-1][0] , f[i-1][1] );
}
}
cout << max({ f[n][0] , f[n][1] , f[n][2] }) << "\n";
return 0;
}
- 求给定序列所有连续子串(长度大于1)异或和的总和
- 拆位计算 + 前缀异或和
- 考虑拆位计算,对于一个区间如果异或和的第 位是1, 说明有奇数个数这一位是1.
- 进而想到维护特定区间某一位出现的1的个数.
- 因为总情况数是 , 所以我们不能一个个求, 但可以用前缀异或和覆盖所有区间, 特定区间1或0的个数同样可以用两个前缀和相减得到.
- 所以先求前缀异或和, 然后对于当前 , 统计第 位和 不一样的在 中有多少个, 总和记为 .
- 最后 .
- 当然由于子串长度要大于 1, 再减去 即可.
- 时间复杂度 . (代码奇短! ! !)
#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l);i<=r;++i)
#define G(i,r,l) for(int i(r);i>=l;--i)
using namespace std;
using ll = long long;
const int N = 3e5 + 105;
const int inf = 0x3f3f3f3f;
int n;
int a[N],num[33][2];
ll ans = 0;
signed main(){
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin>>n; F(i,1,n) cin>>a[i] , a[i] ^= a[i-1] ;
F(i,0,30){ll cnt=0; num[i][0] = 1;
F(j,1,n) cnt += num[i][(((a[j] >> i) & 1) ^ 1)],num[i][((a[j] >> i) & 1)] ++ ;
ans += (1ll<<i) * cnt;
} return cout << ans << "\n",fflush(0),0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】