ABC365(D,E)

ABC365(D,E)

D - AtCoder Janken 3

  • 石头剪刀布,给出对手的出招,问在保证不败的情况下最多能赢多少回
  • fi,0/1/2 表示第 i 局出石头/剪刀/布 , 累计最多赢了多少回回, 直接转移即可
#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;
}

E - Xor Sigma Problem

  • 求给定序列所有连续子串(长度大于1)异或和的总和
  • 拆位计算 + 前缀异或和
  • 考虑拆位计算,对于一个区间如果异或和的第 k 位是1, 说明有奇数个数这一位是1.
  • 进而想到维护特定区间某一位出现的1的个数.
  • 因为总情况数是 O(n2), 所以我们不能一个个求, 但可以用前缀异或和覆盖所有区间, 特定区间1或0的个数同样可以用两个前缀和相减得到.
  • 所以先求前缀异或和, 然后对于当前 i, 统计第 k 位和 pre[i] 不一样的在 pre[1i1] 中有多少个, 总和记为 cnt[k].
  • 最后 ans=i=0302i×cnt[k].
  • 当然由于子串长度要大于 1, 再减去 a[i] 即可.
  • 时间复杂度 O(NlogA). (代码奇短! ! !)
#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;
}
posted @   superl61  阅读(18)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示