2023牛客暑假多校第二场(补题向题解:H)

无数次倒在博弈论下,该好好补补了
5题(D,E,G,I,K) 875分钟

H 0 and 1 in BIT(计组,二进制)

思路

m o d = 2 k mod = 2^k mod=2k k k k x x x 的位数)
一个数 x x x − x -x x 在取模意义下即 x x x 的补码, 反码 = = = 补码 − 1 - 1 1, 题中的翻转操作A即 x x x 的反码, 而B则是正常 + 1 + 1 +1
对于一个 x x x, 对于同一段区间的操作 遇到A则是 − x − 1 -x-1 x1, 遇到B则是 + 1 +1 +1 无论最初 x x x 是什么都是对 x ∗ ( 1 / − 1 ) + x*(1/-1) + x1/1)+ 常数 取模

考虑使用前缀和维护遇到A p r e [ i ] = − p r e [ i − 1 ] − 1 pre[i] = -pre[i - 1] - 1 pre[i]=pre[i1]1 (将 p r e [ i ] pre[i] pre[i] 当做一个数取反) 遇到B p r e [ i ] = p r e [ i − 1 ] + 1 pre[i] = pre[i - 1] + 1 pre[i]=pre[i1]+1

对于求区间 [ l , r ] [l, r] [l,r] 代表的常数时不同于普通前缀和的 p r e [ r ] − p r e [ l − 1 ] pre[r] - pre[l - 1] pre[r]pre[l1]
考虑将 p r e [ l − 1 ] pre[l - 1] pre[l1] 看做最初的 x x x, 往后遇到第1个A − p r e [ l − 1 ] − 1 -pre[l - 1] - 1 pre[l1]1, 第2个A变回来 p r e [ l − 1 ] pre[l - 1] pre[l1], 第3个A再一次取反。

所以要考虑区间 [ l , r ] [l, r] [l,r] 中A的个数,若为奇数则 p r e [ l − 1 ] pre[l - 1] pre[l1] 的贡献为 − p r e [ l − 1 ] -pre[l - 1] pre[l1] ( − 1 -1 1 是本区间的贡献不用减去),那么有 p r e [ l , r ] = p r e [ r ] − ( − p r e [ l − 1 ] ) pre[l, r] = pre[r] - (-pre[l - 1]) pre[l,r]=pre[r](pre[l1])
而偶数个A则与普通前缀和类似。

前缀和代码

#include 
using namespace std;

#define ll long long
const int N = 2e5 + 10;

string s;
int cnt[N], pre[N];

int main(){
    int n, q;
    cin >> n >> q >> s;

   for(int i = 1; i <= n; i ++){
        if(s[i - 1] == 'A'){
            pre[i] = -pre[i - 1] - 1; // 补码 - 1
            cnt[i] = cnt[i - 1] + 1;
        }
        else{
            pre[i] = pre[i - 1] + 1; // 直接 + 1
            cnt[i] = cnt[i - 1];
        }
    }     

    ll ans = 0;
    for(int i = 1; i <= q; i ++){
        ll l, r; string t; 
        cin >> l >> r >> t;

        ll mod = 1LL << t.length(), x = 0;
        for(int i = 0, j = (int)t.length() - 1; i < t.length(); i ++, j --){
        	if(t[i] == '1') x |= (1LL << j);
        }
        l = (l ^ ans) % n + 1;
        r = (r ^ ans) % n + 1;
        if(l > r) swap(l, r);
        
        int sum = cnt[r] - cnt[l - 1]; // 判断区间A数量奇偶
        if(sum & 1){
            ans = (((-x + 1LL * pre[r] + pre[l - 1]) % mod) + mod) % mod;
        }
        else{
            ans = (x + ((1LL * pre[r] - pre[l - 1]) % mod) + mod) % mod;
        }
        for(int i = (int)t.length() - 1; i >= 0; i --){
            if((1LL << i) & ans) cout << "1";
            else cout << "0";
        }
        cout << "\n";
    }
    return 0;
}

线段树维护矩阵(队友代码)

俺不会矩阵

#include
using namespace std;

const int N=2e5+10;
int n,q;
string s;
struct mat{
    long long mp[2][2];
    mat()
    {
        mp[0][0]=0;mp[0][1]=0;
        mp[1][0]=0;mp[1][1]=0;
    }
    mat(int c)
    {
        mp[0][0]=c;mp[0][1]=0;
        mp[1][0]=0;mp[1][1]=c;
    }
    void init1()
    {
        mp[0][0]=-1;mp[0][1]=0;
        mp[1][0]=-1;mp[1][1]=1;
    }
    void init2()
    {
        mp[0][0]=1;mp[0][1]=0;
        mp[1][0]=1;mp[1][1]=1;
    }
    mat operator *(const mat b)
    {
        mat res;
        for(int i=0;i<2;i++)
        {
            for(int j=0;j<2;j++)
            {
                for(int k=0;k<2;k++)
                {
                    res.mp[j][k]=res.mp[j][k]+mp[j][i]*b.mp[i][k];
                }
            }
        }
        return res;
    }
}tr[N<<2];
void build(int k,int l,int r)
{
    if(l==r)
    {
        if(s[l]=='A') {
            tr[k].init1();
        }
        else{
            tr[k].init2();
        }
        return;
    }
    int mi=(l+r)>>1;
    build(k<<1,l,mi);
    build(k<<1|1,mi+1,r);
    tr[k]=tr[k<<1]*tr[k<<1|1];
}
mat qr(int k,int l,int r,int x,int y)
{
    if(l==x&&r==y)
    {
        return tr[k];
    }
    int mi=(l+r)>>1;
    if(y<=mi) return qr(k<<1,l,mi,x,y);
    else if(mi<x) return qr(k<<1|1,mi+1,r,x,y);
    else {
        return qr(k<<1,l,mi,x,mi)*qr(k<<1|1,mi+1,r,mi+1,y);
    }
}
int main()
{
    ios::sync_with_stdio(false);cin.tie(0);
    cout.tie(0);
    cin>>n>>q;
    cin>>s;
    s="_"+s;
    build(1,1,n);
    long long ans=0;
    while(q--)
    {
        long long l,r;
        string s1;
        cin>>l>>r>>s1;
        l=(l^ans)%n+1;
        r=(r^ans)%n+1;
        if(l>r) swap(l,r);
        long long mod=(1ll<<(1ll*s1.size()));
        long long x=0;
        for(int i=0;i<s1.size();i++) x=x*2ll+s1[i]-'0';
        mat res=qr(1,1,n,l,r);
        mat pp;
        pp.mp[0][0]=x;pp.mp[0][1]=1;
        pp=pp*res;
        vector<int>v;
        ans=(pp.mp[0][0]%mod+mod)%mod;
        x=ans;
        for(int i=0;i<s1.size();i++) v.push_back(x%2),x/=2;
        for(int i=v.size()-1;i>=0;i--) cout<<v[i];
        cout<<'\n';
    }
    return 0;
}

你可能感兴趣的:(牛客寒假暑假训练营题解,数论,算法)