[COGS2600] [FJWC2017] 交错和查询

来源:互联网 发布:淘宝手机版怎么看信誉 编辑:程序博客网 时间:2024/05/21 17:15

题意

无限循环数字串S由长度为n的循环节s构成。设s12345(n=5),则数字串S123451234512345
SiS的第i位数字,在上面的例子中,S1=1,S2=2,S6=1
S的一个子串S[l,r]的交错和为sum(l,r)

sum(l,r)=SlSl+1+Sl+2Sl+3++(1)rlSr

sum(2,7)=23+45+12=3

现给定循环节s,要求支持两种操作:
1 pos digit
修改循环节s上的某一位,即将spos改为digit
2 l r
S[l,r]内所有子串的交错和的和

n,m200000;1lr1018;1posn;0digit9
答案对109+7的模。

题解

找规律,发现任意一个询问区间[L,R]对应的答案是,

SLLen+SL+2(Len2)+SL+4(len4)++SL+len0=i=0Len2SL+2i(Len2i)

那么构造四个数列,ji[x]只保存原数列中奇数位置的数字,jiji[x]保存原数列中奇数位置的数字乘它的位置,ou[x],ouou[x]类似。
于是四个数列搞一搞,分情况讨论,最后求一些区间和。树状数组或线段树都可以维护。
下面是树状数组做法。

首先将L,R往前平移,使得L[1,n]中。另外如果数列的长度为奇数,手动模拟时发现比较麻烦,这种情况可以将它加倍,视为一个偶数长度的序列,同时不能忘记修改时修改两个位置,数组大小变为2被。

  • 第一种情况 1LRn此种情况比较简单。
  • 第二种情况1Ln<R2n此种情况将区间拆为[L,n][n+1,R]考虑,也比较简单。
  • 第三种情况1Ln<2n<kn<R(k+1)n此种情况是最麻烦的,首先区间[L,n],[kn,R]可以用类似第二种的方法容易解决,而中间[n,kn]直接找规律即可。我们将一个循环一个循环罗列起来,每一行就是一个循环,现在就是求第2,3,...,k个循环的和。首先列出每个循环的式子,容易看出各个循环的和形成等差数列,可以快速求出。

上面三种情况解决这道题就解决了。
注意的是区间长度,循环个数可能很大,不小心很容易就爆long long。

代码

/// by ztx/// blog.csdn.net/hzoi_ztx#include <bits/stdc++.h>#define Rep(i,l,r) for(i=(l);i<=(r);i++)#define rep(i,l,r) for(i=(l);i< (r);i++)#define Rev(i,r,l) for(i=(r);i>=(l);i--)#define rev(i,r,l) for(i=(r);i> (l);i--)#define Each(i,v)  for(i=v.begin();i!=v.end();i++)#define r(x)   read(x)typedef long long ll ;typedef double lf ;int CH , NEG ;template <typename TP>inline void read(TP& ret) {    ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;    if (CH == '-') NEG = true , CH = getchar() ;    while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;    if (NEG) ret = -ret ;}#define kN  400010LL#define mod 1000000007LL#define half 500000004LL#define lb  (p&(-p))int n, a[kN], ji[kN], ou[kN], jiji[kN], ouou[kN];bool doubled = false;inline void Delta(int p,int w,int c[kN]) {    for (;p<=n;p+=lb) (c[p] += w) %= mod;}inline int Sum(int p,int c[kN]) {    int ret = 0;    for (;p;p-=lb) (ret += c[p]) %= mod;    return ret;}inline int Sum(int p,ll c1,int c[kN],int cc[kN]) {    return (c1%mod * Sum(p,c)%mod + Sum(p,cc))%mod;}inline void Modify(int p,int w) {    if (p&1)        Delta(p,w-a[p],ji),        Delta(p,(a[p]-w)*(p-1),jiji);    else        Delta(p,w-a[p],ou),        Delta(p,(a[p]-w)*(p-2),ouou);    a[p] = w;}inline int calc(int L,int R) {    if (L&1)        return (Sum(R,R-L+1+L-1,ji,jiji)-Sum(L-1,R-L+1+L-1,ji,jiji)) % mod;    else        return (Sum(R,R-L+1+L-2,ou,ouou)-Sum(L-1,R-L+1+L-2,ou,ouou)) % mod;}inline int calcL(int L,ll len) {    if (L&1)        return (Sum(n,len+L-1,ji,jiji)-Sum(L-1,len+L-1,ji,jiji)) % mod;    else        return (Sum(n,len+L-2,ou,ouou)-Sum(L-1,len+L-2,ou,ouou)) % mod;}inline int calcR(int L,ll R,ll len,ll dep) {     if (L&1) {        len = (len+L-1-dep%mod*n%mod)%mod;        return Sum(R-n*dep,len,ji,jiji);    } else {        len = (len+L-2-dep%mod*n%mod)%mod;        return Sum(R-n*dep,len,ou,ouou);    }}inline int calcM(int L,ll len,ll m) {    ll A, B;    len %= mod, m %= mod;    if (L&1) {        A = Sum(n,ji), B = Sum(n,jiji);        return (B*m%mod + (len+L-1LL)%mod*A%mod*m%mod - A*n%mod*m%mod*(m+1)%mod*half%mod)%mod;    } else {        A = Sum(n,ou), B = Sum(n,ouou);        return (B*m%mod + (len+L-2LL)%mod*A%mod*m%mod - A*n%mod*m%mod*(m+1)%mod*half%mod)%mod;    }}inline void Query(ll L,ll R) {    ll ans = 0LL;    if (L > n)        R -= n*((L-1LL)/n), L -= n*((L-1LL)/n);    if (doubled && L>n/2)        L -= n/2, R -= n/2;    if (R <= n) ans = calc(L,R);    else {        ans = calcL(L,(R-L+1));        if (R <= n*2) (ans += calcR(L,R,(R-L+1),1)) %= mod;        else {            (ans += calcR(L,R,(R-L+1),(R-1)/n)) %= mod;            (ans += calcM(L,R-L+1,(R-1)/n-1)) %= mod;        }    }    printf("%lld\n", (ans+mod)%mod);}int main() {    freopen("summ.in","r",stdin);    freopen("summ.out","w",stdout);    int i, p, w, m;    ll L, R;    r(n);    Rep (i,1,n) {        while (CH=getchar(),CH<'!');        a[i] = CH-'0';    }    if (n&1) {        doubled = true;        Rep (i,1,n) a[i+n] = a[i];        n *= 2;    }    Rep (i,1,n) {        if (i&1)            Delta(i,a[i],ji),            Delta(i,-a[i]*(i-1),jiji);        else            Delta(i,a[i],ou),            Delta(i,-a[i]*(i-2),ouou);    }    r(m);    while (m --> 0)        if (r(i), i&1) {            r(p), r(w);            Modify(p,w);            if (doubled) Modify(p+n/2,w);        } else r(L), r(R), Query(L,R);    END: getchar(), getchar();    return 0;}
原创粉丝点击