Caesar Cipher (2020 China Collegiate Programming Contest, Weihai Site)

题目来源

https://codeforces.ml/gym/102798

题意分析

  题目意思的大致可以描述为,给一个长度为n的序列,有两次操作。操作1是将某一区间段的数全部加1,操作2是询问以某两个位置x,y为起点的长度为ln的序列是否相同,进行yes\no的输出。需要注意的是,区间中的所有数字都在[0,65535)这个区间之内。

思路分析

  由操作1想到的是线段树。由操作2想到的是hash。用线段树维护区间的最大值,哈希值和哈希基数值。然后对于操作1来说,就是一个区间修改+区间判断修改(即判断是否出现越界情况)。操作2就是一个区间查询。
  说的很容易,然而还是被这道题上了一课。

code

  1 #include <bits/stdc++.h>
  2 
  3 #define int long long
  4 using namespace std;
  5 const int maxn = 5e5 + 7;
  6 const int pp = 13331;
  7 const int mod = 1e9 + 7;
  8 const int MOD = 65536;
  9 
 10 int a[maxn];
 11 int tree[maxn << 2], ver[maxn << 2], lz[maxn << 2];
 12 int base[maxn << 2], ps[maxn << 2];
 13 
 14 void init(){
 15     base[0] = 1;
 16     for (int i=1; i<maxn; i++) base[i] = base[i-1] * pp % mod;
 17 }
 18 
 19 void pushdown(int p){
 20     if (lz[p]){
 21         lz[p << 1] += lz[p];
 22         lz[p << 1 | 1] += lz[p];
 23         ver[p << 1] = (ver[p << 1] + ps[p << 1] * lz[p]) % mod;
 24         ver[p << 1 | 1] = (ver[p << 1 | 1] + ps[p << 1 | 1] * lz[p]) % mod;
 25         tree[p << 1] += lz[p];
 26         tree[p << 1 | 1] += lz[p];
 27         lz[p] = 0;
 28     }
 29 }
 30 
 31 void build(int p, int l, int r){
 32     if (l == r){
 33         tree[p] = a[l]; ver[p] = (base[l] * a[l]) % mod; ps[p] = base[l];
 34 //    cout << "P:  " << p << " " << tree[p] << " " << ver[p] << " " << ps[p] << endl;
 35         return;
 36     }
 37     int mid = l + r >> 1;
 38     build(p << 1, l, mid);
 39     build(p << 1 | 1, mid + 1, r);
 40     tree[p] = max(tree[p << 1], tree[p << 1 | 1]);
 41     ps[p] = (ps[p << 1] + ps[p << 1 | 1]) % mod;
 42     ver[p] = (ver[p << 1] + ver[p << 1 | 1]) % mod;
 43 //    cout << "P:  " << p << " " << tree[p] << " " << ver[p] << " " << ps[p] << endl;
 44 }
 45 
 46 void update(int p, int l, int r, int L, int R, int x){
 47     if (L <= l && r <= R){
 48         lz[p] += x; tree[p] += x; ver[p] = (ver[p] + ps[p]) % mod;
 49         return;
 50     }
 51 
 52     int mid = l + r >> 1;
 53     pushdown(p);
 54     if (L <= mid) update(p << 1, l, mid, L, R, x);
 55     if (mid < R) update(p << 1 | 1, mid + 1, r, L, R, x);
 56     tree[p] = max(tree[p << 1], tree[p << 1 | 1]);
 57     ver[p] = (ver[p << 1] + ver[p << 1 | 1]) % mod;
 58 }
 59 
 60 void umod(int p, int l, int r){
 61 //    cout << p << " " << tree[p] << " " << l << " " << r << " %%%%\n";
 62     if (tree[p] < MOD) return;
 63     if (l == r){
 64         tree[p] = 0;
 65         ver[p] = 0; lz[p] = 0;
 66         return;
 67     }
 68     pushdown(p);
 69     int mid = l + r >> 1;
 70     umod(p << 1, l, mid);
 71     umod(p << 1 | 1, mid + 1, r);
 72     tree[p] = max(tree[p << 1], tree[p << 1 | 1]);
 73     ver[p] = (ver[p << 1] + ver[p << 1 | 1]) % mod;
 74 }
 75 
 76 int ask(int p, int l, int r, int L, int R){
 77     if (L <= l && r <= R) {
 78 //        cout << "p" << p <<endl;
 79         return ver[p];
 80     }
 81     int mid = l + r >> 1;
 82     pushdown(p);
 83     int ans = 0;
 84     if (L <= mid) ans += ask(p << 1, l, mid, L, R);
 85     ans %= mod;
 86     if (mid < R) ans += ask(p << 1 | 1, mid + 1, r, L, R);
 87     ans %= mod;
 88     return ans;
 89 }
 90 
 91 signed main(){
 92     init();
 93     int n, q; scanf("%lld%lld", &n, &q);
 94     for (int i=1; i<=n; i++) scanf("%lld", &a[i]);
 95     build(1, 1, n);
 96 
 97 
 98 
 99     while (q --){
100         int op; scanf("%lld", &op);
101         if (op == 1){
102             int l, r; scanf("%lld%lld", &l, &r);
103             update(1, 1, n, l, r, 1);
104             umod(1, 1, n);
105 
106 //            cout << ask(1, 1, n, 1, 1) << " " << ask(1, 1, n, 2, 2) << " " << ask(1, 1, n, 3, 3) << endl;
107 
108         }else {
109             int x, y, ln;
110             scanf("%lld%lld%lld", &x, &y, &ln);
111             if (x > y) swap(x, y);
112             int ans1 = ask(1, 1, n, x, x + ln - 1);
113 //            cout << "&&&&&&" << endl;
114 //            cout << x << " " << x+ln << endl;
115             int ans2 = ask(1, 1, n, y, y + ln - 1);
116 //            cout << "ans1: " << ans1 << endl;
117             ans1 = ans1 * base[y-x] % mod;
118 //            cout << "ans1: " << ans1 << " ans2: " << ans2 << endl;
119             if (ans1 == ans2) printf("yes\n");
120             else printf("no\n");
121         }
122     }
123     return 0;
124 }
125 /*
126 5 1
127 1 2 1 2 1
128 2 1 3 3
129 
130 3 2
131 0 65535 65535
132 1 2 3
133 2 1 2 2
134 */
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值