Problem 2 交错和查询

来源:互联网 发布:单片机 usb 虚拟串口 编辑:程序博客网 时间:2024/05/22 06:31

【题目描述】

 

无限循环数字串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);}

0 0