题解:P14510 夜里亦始终想念着你 miss
验题人题解。想这个题的时候思路有点乱,可能导致做法比较冗长。
“段” 指的是 1 的连续段。
有一些观察:操作可逆、在右侧没有 1 时可以将一个长度为偶数的段整体右移一位。
首先操作是可逆的,所以不妨先将尽可能多的 1 挪到最左边形成一个较长的段,然后拿这个段去把 1。(由于只有长度为偶数的段可以整体移动,如果开头段长为奇数就把最后一个位置当成单个的看待)
设段长为 1 的个数为
把段从左往右滑动,记目前段开头位置为 1 且 1,而这会导致
设
注意到
把式子写出来:
时间复杂度为
代码和题解有一点出入。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int mod=1e9+7;
int iv2,n,m,s1,a[500005],nv=-1,cnt,nlen,ans,fac[500005],inv[500005],pw[500005],ip[500005];
string s;
set<pair<int,int>> st;
inline int Pow(int x,int y){
int res=1;
for(;y;y>>=1,x=1ll*x*x%mod)
if(y&1)
res=1ll*res*x%mod;
return res;
}
int C(int n,int m){
if(!m) return 1;
if(n<m||m<0) return 0;
return 1ll*fac[n]*inv[m]%mod*inv[n-m]%mod;
}
void mv(int len,int v){
while(nlen<len) ans=(ans*2ll-1ll*C(nlen+nv,nv)*ip[nv])%mod,nlen++;
while(nlen>len) nlen--,ans=1ll*iv2*(ans+1ll*C(nlen+nv,nv)*ip[nv]%mod)%mod;
while(nv<v) nv++,ans=(ans+1ll*C(len+nv-1,nv)*ip[nv])%mod;
while(nv>v) ans=(ans-1ll*C(len+nv-1,nv)*ip[nv])%mod,nv--;
}
void solve(){
if(cnt==s1){
cout<<pw[cnt]<<'\n';
return ;
}
int p1=s1-cnt+1,len=n+1-p1-cnt,v=p1/2,rv=v*2;
mv(len,v),ans=(ans+mod)%mod;
cout<<1ll*ans*pw[cnt+rv]%mod<<'\n';
}
int main(){
// freopen("miss3.in","r",stdin);
// freopen("D.out","w",stdout);
ios::sync_with_stdio(0),cin.tie(0);
cin>>n>>m>>s,iv2=Pow(2,mod-2);
for(int i=1;i<=n;i++) a[i]=s[i-1]-'0';
for(int i=1,len=0;i<=n;i++)
if(a[i]){
len++,s1++;
if(!a[i+1]) cnt+=(len&1),st.insert({i-len+1,i}),len=0;
}
fac[0]=pw[0]=ip[0]=1;
for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%mod,pw[i]=2*pw[i-1]%mod,ip[i]=1ll*ip[i-1]*iv2%mod;
inv[n]=Pow(fac[n],mod-2);
for(int i=n-1;~i;i--) inv[i]=1ll*inv[i+1]*(i+1)%mod;
solve();
for(int x;m--;){
cin>>x;
if(a[x]){
s1--;
auto [l,r]=*--st.upper_bound({x,n+1});
cnt-=((l&1)==(r&1));
st.erase({l,r});
if(l<x) cnt+=((l&1)!=(x&1)),st.insert({l,x-1});
if(x<r) cnt+=((r&1)!=(x&1)),st.insert({x+1,r});
}
else{
s1++;
auto it=st.upper_bound({x,x});
int nr=x,nl=x,l=-1,r=-1;
if(it!=st.end()){
l=(*it).first,r=(*it).second;
if(l==x+1) nr=r;
else l=r=-1;
}
if(it!=st.begin()){
it--;
int L=(*it).first,R=(*it).second;
if(R==x-1) nl=L,st.erase({L,R}),cnt-=((L&1)==(R&1));
}
if(l!=-1) cnt-=((l&1)==(r&1)),st.erase({l,r});
st.insert({nl,nr}),cnt+=((nl&1)==(nr&1));
}
a[x]^=1;
solve();
}
return 0;
}