题意:
给一个字符串,求所有1之间距离的和,之后给q组修改,每次把一个位置上的0改成1或者1改成0,求出每次修改之后的答案
思路:
设cnti 为从1到i这段字符串中1的个数,sumi 为从1到i中1位置的和
假设修改的位置为i,这答案的改变值为[cnt(1-i) * i - sum(1-i)] + [sum(i+1 - n) - i*cnt(i+1 - n)]
特别要注意取模的问题:(ans%mod+mod)%mod;
#include<iostream> #include<algorithm> using namespace std; typedef long long ll; const int maxn=1e5+10; const int mod=1e9+7; char s[maxn]; ll num[maxn],sum[maxn]; int n,m; int lowbit(int x){return x&(-x);} void add(int x,ll val) { while(x<=maxn){ sum[x]+=val; x+=lowbit(x); } } ll query(int x)//算sum { ll ans=0; while(x>=1){ ans+=sum[x]; x-=lowbit(x); ans%=mod; } return ans%mod; } void add1(int x,ll val) { while(x<=maxn){ num[x]+=val; x+=lowbit(x); } } ll query1(int x)//算cnt { ll ans=0; while(x>=1){ ans+=num[x]; x-=lowbit(x); } return ans%mod; } int main() { scanf("%d%s",&n,s+1); ll ans=0,cnt=0,su=0; for(int i=1;i<=n;i++){ if(s[i]=='1'){ ans+=(cnt*i-su)%mod; cnt++; su+=i; ans%=mod,su%=mod; add(i,i); add1(i,1); } } cout<<(ans%mod+mod)%mod<<endl; scanf("%d",&m); while(m--){ int op,pos; scanf("%d%d",&op,&pos); if(op==1){ if(s[pos]=='1') continue; else{ ll xx=pos*query1(pos-1)-query(pos-1)+(query(n)-query(pos))-pos*(query1(n)-query1(pos)); ans+=xx%mod; add(pos,pos),add1(pos,1); cout<<(ans%mod+mod)%mod<<endl; s[pos]='1'; } } else{ if(s[pos]=='0') continue; else{ ll xx=pos*query1(pos-1)-query(pos-1)+(query(n)-query(pos))-pos*(query1(n)-query1(pos)); ans-=xx%mod; add(pos,-pos),add1(pos,-1); cout<<(ans%mod+mod)%mod<<endl; s[pos]='0'; } } } return 0; }