无数次倒在博弈论下,该好好补补了
5题(D,E,G,I,K) 875分钟
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 −x−1, 遇到B则是 + 1 +1 +1 无论最初 x x x 是什么都是对 x ∗ ( 1 / − 1 ) + x*(1/-1) + x∗(1/−1)+ 常数 取模
考虑使用前缀和维护遇到A p r e [ i ] = − p r e [ i − 1 ] − 1 pre[i] = -pre[i - 1] - 1 pre[i]=−pre[i−1]−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[i−1]+1。
对于求区间 [ l , r ] [l, r] [l,r] 代表的常数时不同于普通前缀和的 p r e [ r ] − p r e [ l − 1 ] pre[r] - pre[l - 1] pre[r]−pre[l−1]
考虑将 p r e [ l − 1 ] pre[l - 1] pre[l−1] 看做最初的 x x x, 往后遇到第1个A − p r e [ l − 1 ] − 1 -pre[l - 1] - 1 −pre[l−1]−1, 第2个A变回来 p r e [ l − 1 ] pre[l - 1] pre[l−1], 第3个A再一次取反。
所以要考虑区间 [ l , r ] [l, r] [l,r] 中A的个数,若为奇数则 p r e [ l − 1 ] pre[l - 1] pre[l−1] 的贡献为 − p r e [ l − 1 ] -pre[l - 1] −pre[l−1] ( − 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[l−1])。
而偶数个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;
}