ABC365(D,E)

ABC365(D,E)

D - AtCoder Janken 3

  • 石头剪刀布,给出对手的出招,问在保证不败的情况下最多能赢多少回
  • \(f_i,{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(n^2)\), 所以我们不能一个个求, 但可以用前缀异或和覆盖所有区间, 特定区间1或0的个数同样可以用两个前缀和相减得到.
  • 所以先求前缀异或和, 然后对于当前 \(i\), 统计第 \(k\) 位和 \(pre[i]\) 不一样的在 \(pre[1 \sim i-1]\) 中有多少个, 总和记为 \(cnt[k]\).
  • 最后 \(ans = \sum_{i=0}^{30} 2^i \times cnt[k]\).
  • 当然由于子串长度要大于 1, 再减去 \(\sum 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 @ 2024-08-04 21:20  superl61  阅读(40)  评论(0)    收藏  举报