题意
无限循环数字串
S
由长度为
设
Si
为
S
的第
设
S
的一个子串
如 sum(2,7)=2−3+4−5+1−2=−3
现给定循环节
s
,要求支持两种操作:
修改循环节
s
上的某一位,即将
2 l r
:
求
S[l,r]
内所有子串的交错和的和
n,m≤200000;1≤l≤r≤1018;1≤pos≤n;0≤digit≤9
答案对
109+7
的模。
题解
找规律,发现任意一个询问区间 [L,R] 对应的答案是,
那么构造四个数列, ji[x] 只保存原数列中奇数位置的数字, jiji[x] 保存原数列中奇数位置的数字乘它的位置, ou[x],ouou[x] 类似。
于是四个数列搞一搞,分情况讨论,最后求一些区间和。树状数组或线段树都可以维护。
下面是树状数组做法。
首先将
L,R
往前平移,使得
L
在
- 第一种情况 1≤L≤R≤n 此种情况比较简单。
- 第二种情况 1≤L≤n<R≤2n 此种情况将区间拆为 [L,n] 与 [n+1,R] 考虑,也比较简单。
- 第三种情况 1≤L≤n<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;
}