zoukankan      html  css  js  c++  java
  • 五月月赛 寻宝 exkmp + 主席树

    2121: 寻宝
    时间限制: 1 Sec  内存限制: 128 MB
    提交: 11  解决: 4
    [提交] [状态] [讨论版] [命题人:admin]
    题目描述
    采蘑菇的小西佬找到了一张上古年间的藏宝图,上面画着m座连绵不断的山,他决定去地图上记载的地点探险,可当他到达时,他发现当地其实有n座山,并且由于年代久远有些山也改变了形状,他不能准确的找到地图上藏宝的地点,于是他决定从一些连续的山中随意选择一座山作为地图上的第一个点,当他选定了起点以后,若当前的山与地图上记载山的高度相同他就会继续前往下一座山,否则就停下来,直到他到达地图上的最后一座山位置。我们假设如果他经过了大于k座山他就能找到宝藏(如果第一座山高度就不相同,视为经过0座山),现在的问题就是他有多大的可能性找到宝藏。 
    题目共有q次询问,每次询问有两个整数l,r代表采蘑菇的小西佬选择的区间,并且会给出第一次询问的k,之后的每个询问的k按照下面的式子算出 
                         k=(ans*10086666)%x; 
      
    ans代表上一次询问的答案,x=min(m,r-l+); 
    
    
    输入
    第一行输入三个数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+); 
    题面

    用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
    ", ans);
                }
    
                return 0;
    }
    View Code
  • 相关阅读:
    android如何从网络中获取数据
    如何写好代码
    如何有效遍历集合中的对象
    Android中自定义控件
    Android如何从网络中获取图片
    如果对象的类型为T1,就做某件事;如果对象的类型为T2,就做另外一件事,请赏自己一个巴掌
    android如何在网络中获取数据
    android shell脚本使用
    ASP.NET应用程序
    php记住用户名和密码实现代码(cookie)
  • 原文地址:https://www.cnblogs.com/ckxkexing/p/10926254.html
Copyright © 2011-2022 走看看