五月月赛 寻宝 exkmp + 主席树
作者:互联网
2121: 寻宝 时间限制: 1 Sec 内存限制: 128 MB 提交: 11 解决: 4 [提交] [状态] [讨论版] [命题人:admin] 题目描述 采蘑菇的小西佬找到了一张上古年间的藏宝图,上面画着m座连绵不断的山,他决定去地图上记载的地点探险,可当他到达时,他发现当地其实有n座山,并且由于年代久远有些山也改变了形状,他不能准确的找到地图上藏宝的地点,于是他决定从一些连续的山中随意选择一座山作为地图上的第一个点,当他选定了起点以后,若当前的山与地图上记载山的高度相同他就会继续前往下一座山,否则就停下来,直到他到达地图上的最后一座山位置。我们假设如果他经过了大于k座山他就能找到宝藏(如果第一座山高度就不相同,视为经过0座山),现在的问题就是他有多大的可能性找到宝藏。 题目共有q次询问,每次询问有两个整数l,r代表采蘑菇的小西佬选择的区间,并且会给出第一次询问的k,之后的每个询问的k按照下面的式子算出 k=(ans*10086+666)%x; ans代表上一次询问的答案,x=min(m,r-l+1); 输入 第一行输入三个数n,m,k(1<=n,m,k<=1e5); 第二行输入n个数代表n座山的高度(1<=a[i]<=1e9) 第二行输入m个数代表m座山的高度(1<=b[i]<=1e9) 第四行输入一个数q;(1<=q<=1e5) 接下来每行输入两个整数l,r;(1<=l<=r<=n) 输出 对于每个询问请输出对应的概率,以逆元的形式输出(mod=1e9+7);题面
用exkmp预处理出每个点可以向后面跑的长度,由于k是变化的,所以需要主席树来回答。
#include <bits/stdc++.h> using namespace std; #define pb push_back #define fi first #define se second #define debug(x) cerr<<#x << " := " << x << endl; #define bug cerr<<"-----------------------"<<endl; typedef long long ll; typedef long double ld; typedef pair<int, int> pii; typedef pair<ll, ll> pll; //const int inf = 0x3f3f3f3f; const int mod = 1e9+7; /**********showtime************/ const int N = 1e5 + 5; int nxt[N], ex[N]; int S[N], P[N]; int a[N]; int n,m,k; void GETNEXT() { int i = 0, j, po, len=m; nxt[0] = len; while(P[i] == P[i+1] && i+1 < len) i++; nxt[1] = i; po = 1; for(i = 2; i < len; i++) { if(nxt[i-po] + i < nxt[po] + po) nxt[i] = nxt[i-po]; else { j=nxt[po] + po - i; if(j < 0) j = 0; while(i + j < len && P[j] == P[j+i]) j++; nxt[i] = j; po = i; } } } void EXKMP() { int i = 0, j, po, len = n, l2 = m; while(S[i] == P[i] && i < l2 && i < len) i++; ex[0] = i; po = 0; for(i = 1; i < len; i++) { if(nxt[i-po] + i < ex[po] + po) ex[i]=nxt[i-po]; else { j = ex[po] + po - i; if(j < 0) j = 0; while(i + j < len && j < l2 && S[j+i] == P[j]) j++; ex[i] = j; po = i; } } } struct node{ int le, ri; int cnt; } tree[N * 20]; int tot = 0; int root[N]; int build(int le, int ri) { int p = ++tot; if(le == ri) { tree[p].cnt = 0; return p; } int mid = (le + ri) >> 1; tree[p].le = build(le, mid); tree[p].ri = build(mid+1, ri); tree[p].cnt = tree[tree[p].le].cnt + tree[tree[p].ri].cnt; return p; } int ins(int now, int le, int ri, int x, int val) { int p = ++tot; tree[p] = tree[now]; if(le == ri) { tree[p].cnt += val; return p; } int mid = (le + ri) >> 1; if(x <= mid) { tree[p].le = ins(tree[now].le, le, mid, x, val); } else { tree[p].ri = ins(tree[now].ri, mid+1, ri, x, val); } tree[p].cnt = tree[tree[p].le].cnt + tree[tree[p].ri].cnt; return p; } int query(int L, int R, int le, int ri, int rt1, int rt2) { if(L > R) return 0; if(le >= L && ri <= R) { return tree[rt2].cnt - tree[rt1].cnt; } int res = 0; int mid = (le + ri) >> 1; if(mid >= L) res += query(L, R, le, mid, tree[rt1].le, tree[rt2].le); if(mid < R) res += query(L, R, mid+1, ri, tree[rt1].ri, tree[rt2].ri); return res; } ll ksm(ll a, ll n) { ll res = 1; while(n > 0) { if(n & 1) res = res * a % mod; a = a * a % mod; n = n>>1; } return res; } int main(){ scanf("%d%d%d", &n, &m, &k); for(int i=0; i<n; i++) scanf("%d", &S[i]); for(int i=0; i<m; i++) scanf("%d", &P[i]); GETNEXT(); EXKMP(); root[0] = build(1, n); for(int i=0; i < n; i++){ root[i+1] = ins(root[i], 1, n, ex[i]+1, 1); } int q; scanf("%d", &q); int ans = 0; for(int i=1; i<=q; i++) { int l, r; scanf("%d%d", &l, &r); if(i > 1) { int x = min(m, r - l + 1); k = (1ll*ans * 10086 + 666) % x; } int c = query(k+2, n, 1, n, root[l-1], root[r]); // cout<<c << " " << k << endl; ans = 1ll*c * ksm(r - l + 1, mod-2) % mod; printf("%d\n", ans); } return 0; }View Code
标签:exkmp,月赛,le,nxt,int,tree,寻宝,ri,po 来源: https://www.cnblogs.com/ckxkexing/p/10926254.html