专栏文章
题解:P14510 夜里亦始终想念着你 miss
P14510题解参与者 2已保存评论 1
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 1 条
- 当前快照
- 1 份
- 快照标识符
- @min7lhvt
- 此快照首次捕获于
- 2025/12/01 21:52 3 个月前
- 此快照最后确认于
- 2025/12/01 21:52 3 个月前
验题人题解。想这个题的时候思路有点乱,可能导致做法比较冗长。
“段” 指的是
1 的连续段。有一些观察:操作可逆、在右侧没有
1 时可以将一个长度为偶数的段整体右移一位。首先操作是可逆的,所以不妨先将尽可能多的
1 挪到最左边形成一个较长的段,然后拿这个段去把 填上。这时候的局面是左侧有一个长段,然后会剩下一些单个的 1。(由于只有长度为偶数的段可以整体移动,如果开头段长为奇数就把最后一个位置当成单个的看待)设段长为 ,单个
1 的个数为 ,位置为 ,令 。把段从左往右滑动,记目前段开头位置为 。考虑段的长度是怎么衰减的,发现当且仅当限制要求 这一位为
1 且 并非单个的 1,而这会导致 。这启示我们考虑段尾从 走到 的变化(因为段尾为 会导致 不减少)。设 表示现在有连续的 个位置可以让 ,最终 的方案数。有 ,。设 表示段长最后为 的方案数,则把所有 卷起来即可。由于滑到末尾后剩下的位置可以乱填,且每个 会“保护”一个位置,最后答案为 。暴力 dp 复杂度为 ,但是可以通过 的点。
注意到 ,把 提出来后相当于是从 走到 的方案数。,相当于 乘上 到 的方案数。所以 ,容易 计算。这样就可以 计算答案了。
时间复杂度为 。
代码和题解有一点出入。
CPP#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;
}
相关推荐
评论
共 1 条评论,欢迎与作者交流。
正在加载评论...