【题目描述】
无限循环数字串S由长度为n的循环节s构成。设s为12345(n=5),则数字串S为123451234512345…
设Si为S的第i位数字,在上面的例子中,S1=1,S2=2,S6=1。
设S的一个子串S[l,r]的交错和为sum(l,r):
sum(l,r) = Sl - S1+1 + Sl+2- Sl+3 + … + (-1)r-lSr
如sum(2,7) = 2 - 3 + 4 - 5 + 1 - 2 = -3
现给定循环节s,要求支持两种操作:
1pos digit:
修改循环节s上的某一位,即将spos改为digit。
2 l r:
求S[l,r]内所有子串的交错和的和,即
输出ans对109+7的模。
【输入格式】
第一行一个整数n,表示循环节s的长度。
第二行一个长度为n的数字串,表示循环节s。
第三行一个整数m,表示操作次数。
以下m行,每行3个整数。
若第一个数为1,表示是修改操作1 pos digit。
若第一个数为2,表示是询问操作2 l r。
【输出格式】
对于每个询问操作输出一行,表示答案。
【样例输入】
5
12345
5
2 1 5
2 6 10
1 3 5
2 1 5
2 1 6
【样例输出】
19
19
25
36
【数据范围】
对于10%的数据点,n, m <= 50;
对于20%的数据点,n, m <=1000;
对于40%的数据点,1 <= l<= r <= n;
对于100%的数据点,n, m <=200000;1 <= l <= r <= 1018;1 <= pos <= n;0 <= digit <= 9;
通过分析或者带入样例可发现答案为s[i]*(r - i+1), 其中l<=i<=r;
通过拆式子可化为s[i]*r-s[i]*i+s[i],对于40分我们直接线段树。
对于100分我们把序列拆成3段,分别为[l,an],[an + 1, bn],[bn + 1, r],中间那个就是个等差数列。
说起来真他妈简单(这傻逼被这题卡了6个半小时)
注意MOD,其中有的是longlong*int,所以一定要注意(这傻逼后面2小时一直都在查,最后发现longlong*int爆了)。如果小数据能过大数据过不去八成就是这个问题。
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int MAXN = 400005;
const int MOD = 1000000007;
char c[MAXN];
int n, i, j, k, m, a[MAXN << 1], ty, sum[MAXN << 2][4], tot1, tot2, ans;
long long l, r;
inline int get()
{
char c;
while ((c = getchar()) < 48 || c > 57);
int res = c - 48;
while ((c = getchar()) >= 48 && c <= 57)
res = res * 10 + c - 48;
return res;
}
inline long long get1()
{
char c;
while ((c = getchar()) < 48 || c > 57);
long long res = c - 48;
while ((c = getchar()) >= 48 && c <= 57)
res = res * 10 + c - 48;
return res;
}
inline int ksm(int x, int y)
{
if (!y) return 1;
int tmd = ksm(x, y >> 1);
tmd = (long long)tmd * tmd % MOD;
if (y & 1) tmd = tmd * (long long)x % MOD;
return tmd;
}
inline void change(int &x)
{
if (x >= MOD) x -= MOD;
}
inline void updata(int k)
{
sum[k][0] = sum[k << 1][0] + sum[k << 1 | 1][0]; change(sum[k][0]);
sum[k][1] = sum[k << 1][1] + sum[k << 1 | 1][1]; change(sum[k][1]);
sum[k][2] = sum[k << 1][2] + sum[k << 1 | 1][2]; change(sum[k][2]);
sum[k][3] = sum[k << 1][3] + sum[k << 1 | 1][3]; change(sum[k][3]);
}
inline void maketree(int k, int p, int q)
{
if (p == q)
{
if (p & 1) sum[k][0] = a[p] * (long long)p % MOD, sum[k][1] = a[p];
else sum[k][2] = a[p] * (long long)p % MOD, sum[k][3] = a[p];
return;
}
int mid = (p + q) >> 1;
maketree(k << 1, p, mid);
maketree(k << 1 | 1, mid + 1, q);
updata(k);
}
inline void change(int k, int p, int q, int w, int w1)
{
if (p == q)
{
if (p & 1) sum[k][0] = p * (long long)w1 % MOD, sum[k][1] = w1;
else sum[k][2] = p * (long long)w1 % MOD, sum[k][3] = w1;
return;
}
int mid = (p + q) >> 1;
if (mid >= w) change(k << 1, p, mid, w, w1);
if (mid < w) change(k << 1 | 1, mid + 1, q, w, w1);
updata(k);
}
inline void find(int k, int p, int q, int l, int r, int w)
{
if (p >= l && q <= r)
{
if (w) tot1 += sum[k][0], tot2 += sum[k][1];
else tot1 += sum[k][2], tot2 += sum[k][3];
change(tot1); change(tot2);
return;
}
int mid = (p + q) >> 1;
if (mid >= l) find(k << 1, p, mid, l, r, w);
if (mid < r) find(k << 1 | 1, mid + 1, q, l, r, w);
}
int main()
{
freopen("sum.in", "r", stdin);
freopen("sum.out", "w", stdout);
cin >> n;
scanf("%s", c + 1);
for(i = 1; i <= n; i ++)
a[i] = c[i] - 48;
maketree(1, 1, n);
cin >> m;
while (m --)
{
ty = get();
if (ty == 1)
{
int x = get(), y = get();
change(1, 1, n, x, y);
}
else
{
l = get1(); r = get1();
long long blockl = l / n + (l % n != 0), blockr = r / n + (r % n != 0);
int ll = (l - 1) % n + 1;
int rr = (r - 1) % n + 1;
long long t = (blockl - 1) * n;
ans = 0;
if (blockl == blockr)
{
tot1 = tot2 = 0;
find(1, 1, n, ll, rr, ll & 1);
int part1 = r % MOD * tot2 % MOD;
int part2 = tot1 + t % MOD * tot2 % MOD;
change(part2);
int part3 = tot2;
ans = part1 - part2 + part3;
if (ans < 0) ans += MOD;
change(ans);
printf("%d\n", ans);
continue;
}
tot1 = tot2 = 0;
find(1, 1, n, ll, n, ll & 1);
int part1 = r % MOD * tot2 % MOD;
int part2 = tot1 + t % MOD * tot2 % MOD;
change(part2);
int part3 = tot2;
int ans1 = part1 - part2 + part3;
change(ans1);
if (ans1 < 0) ans1 += MOD;
long long fp = (r - l - ((r - 1) % n + 1)) & 1;
tot1 = tot2 = 0;
t = (blockr - 1) * n;
find(1, 1, n, 1, rr, fp);
part1 = r % MOD * tot2 % MOD;
part2 = tot1 + t % MOD * tot2 % MOD;
change(part2);
part3 = tot2;
int ans2 = part1 - part2 + part3;
change(ans2);
if (ans2 < 0) ans2 += MOD;
ans = ans1 + ans2;
change(ans);
t = (blockr - blockl - 1) * n;
tot1 = tot2 = 0;
find(1, 1, n, 1, n, (n - ll) & 1);
int pre1 = tot1, pre2 = tot2;
if ((blockr - blockl - 1) & 1)
{
t = (blockr - 2) * n;
part1 = r % MOD * tot2 % MOD;
part2 = (long long)tot1 + t % MOD * tot2 % MOD;
change(part2);
part3 = tot2;
ans1 = part1 - part2 + part3;
change(ans1);
ans += ans1;
change(ans);
if (ans < 0) ans += MOD;
}
tot1 = tot2 = 0;
if (n & 1) find(1, 1, n, 1, n, (n - ll + 1) & 1);
else find(1, 1, n, 1, n, (n - ll) & 1);
tot1 = ((long long)pre1 + (long long)tot2 * n % MOD) % MOD + tot1;
change(tot1);
tot2 += pre2; change(tot2);
t = blockl * n;
part1 = r % MOD * (long long)tot2 % MOD;
part2 = (long long)tot1 + t % MOD * (long long)tot2 % MOD;
change(part2);
part3 = tot2;
long long tim = (blockr - blockl - 1) >> 1;
if (!tim) {printf("%d\n", ans); continue;}
part1 = tim % MOD * part1 % MOD;
part3 = tim % MOD * part3 % MOD;
int d = 2 * n * (long long)tot2 % MOD, mo = (tim - 1) % MOD * (long long)d % MOD + part2;
change(mo);
part2 = tim % MOD * (part2 + mo) % MOD * (long long)ksm(2, MOD - 2) % MOD;
ans1 = part1 - part2 + part3;
change(ans1);
ans += ans1;
change(ans);
if (ans < 0) ans += MOD;
printf("%d\n", ans);
}
}
fclose(stdin); fclose(stdout);
}