• CCPC2019网络赛


    2019中国大学生程序设计竞赛(CCPC) - 网络选拔赛

    A

    题意:找到最小的正整数 C 使得 (AC)&(BC) 最小。 (A,B le 10^9)

    签到题。这个C取 A&B 时为 0 ,并且此时也是最小的。注意要正整数,所以要跟 1 取 max。

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    typedef long double LD;
    typedef pair<int,int> pii;
    typedef pair<LL,int> pli;
    typedef pair<LL,LL> pll;
    const int SZ = 1e6 + 10;
    const int INF = 1e9 + 10;
    const int mod = 1e9 + 7;
    const LD eps = 1e-8;
    
    LL read() {
        LL n = 0;
        char a = getchar();
        bool flag = 0;
        while(a > '9' || a < '0') { if(a == '-') flag = 1; a = getchar(); }
        while(a <= '9' && a >= '0') { n = n * 10 + a - '0',a = getchar(); }
    	if(flag) n = -n;
    	return n;
    }
    
    LL work(LL n,LL m) {
        for(LL k = 0;;k ++) {
            if(((n^k)&(m^k)) == 0) return k;
        }
    }
    
    int main() {
        int T = read();
        while(T --) {
            LL n,m;
            scanf("%lld%lld",&n,&m);
            printf("%lld
    ",max(1ll,n&m));
        }
    }
    
    

    B

    题意:给一个排列,每次操作是给某个 (a_x += 10^7) ,或者询问最小的 v 使得其大于等于 (k_i) 且不等于任何一个 (a_j)((1le jle r_i))(k_i le n le 10^5)

    key:线段树

    对值域建线段树,每个点存这个数字的出现位置。每次修改操作实际上可以看做出现位置在无穷大处。每次即找一个最小的右端点 x,使得 [k,x] 的最大值大于 r。

    由于线段树自带二分性,所以可以直接找,复杂度 (O(nlog n))

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    typedef long double LD;
    typedef pair<int,int> pii;
    typedef pair<LL,int> pli;
    typedef pair<LL,LL> pll;
    const int SZ = 1e6 + 10;
    const int INF = 1e9 + 10;
    const int mod = 1e9 + 7;
    const LD eps = 1e-8;
    
    LL read() {
        LL n = 0;
        char a = getchar();
        bool flag = 0;
        while(a > '9' || a < '0') { if(a == '-') flag = 1; a = getchar(); }
        while(a <= '9' && a >= '0') { n = n * 10 + a - '0',a = getchar(); }
    	if(flag) n = -n;
    	return n;
    }
    
    int a[SZ];
    
    struct seg {
        int l,r,mx;
    }tree[SZ * 4];
    
    void update(int p) {
        tree[p].mx = max(tree[p<<1].mx,tree[p<<1|1].mx);
    }
    
    void build(int p,int l,int r) {
        tree[p].l = l;
        tree[p].r = r;
        if(l == r) {
            tree[p].mx = a[l];
            return ;
        }
        int mid = l + r >> 1;
        build(p<<1,l,mid);
        build(p<<1|1,mid+1,r);
        update(p);
    }
    
    void change(int p,int x,int d) {
        if(tree[p].l == tree[p].r) {
            tree[p].mx = d;
            return ;
        }
        int mid = tree[p].l + tree[p].r >> 1;
        if(x <= mid) change(p<<1,x,d);
        else change(p<<1|1,x,d);
        update(p);
    }
    
    int ask_max(int p,int l,int r) {
        if(l <= tree[p].l && tree[p].r <= r) {
            return tree[p].mx;
        }
        int mid = tree[p].l + tree[p].r >> 1,ans = 0;
        if(l <= mid) ans = max(ans,ask_max(p<<1,l,r));
        if(mid < r) ans = max(ans,ask_max(p<<1|1,l,r));
        return ans;
    }
    
    int n,m;
    
    int ask(int p,int l,int v) {
       // printf("%d [%d,%d] %d %d
    ",p,tree[p].l,tree[p].r,l,v);
        if(tree[p].l == l) {
            if(tree[p].l == tree[p].r) {
                if(tree[p].mx <= v) return -1;
            //    cout << tree[p].l << endl;
                return tree[p].l;
            }
         //   printf("%d
    ",tree[p<<1].mx);
            if(tree[p<<1].mx > v) return ask(p<<1,l,v);
            int mid = tree[p].l + tree[p].r >> 1;
            return ask(p<<1|1,mid+1,v);
        }
        int mid = tree[p].l + tree[p].r >> 1;
        if(mid < l) {
            return ask(p<<1|1,l,v);
        }
        else {
            int ans = ask(p<<1,l,v);
            if(ans != -1) return ans;
            return ask(p<<1|1,mid+1,v);
        }
    }
    
    int b[SZ];
    
    int main() {
       // freopen("02.out","w",stdout);
        int T = read();
        while(T --) {
            n = read(),m = read();
            for(int i = 1;i <= n;i ++) a[b[i] = read()] = i;
            build(1,1,n);
            int lstans = 0;
            while(m --) {
                int o = read();
                if(o == 1) {
                    int x = read() ^ lstans;
                    if(b[x] == 1e9) continue;
                    change(1,b[x],1e9);
                    b[x] = 1e9;
                }
                else {
                    int r = read() ^ lstans,k = read() ^ lstans;
                    int ans = ask(1,k,r);
                    if(ans == -1) ans = n+1;
                    printf("%d
    ",lstans = ans);
                }
            }
        }
    }
    
    

    C

    题意:给一个字符串,每次询问一个区间的子串在整个字符串中出现第 k 次的位置。 (n,Q le 10^5)

    key:st表,后缀数组,主席树

    想到后缀数组就差不多了,应该还有sam之类的做法,不过我不太会定位这个区间在sam中的位置……

    后缀数组找到当前区间在lcp中的位置,向左右用rmq二分找到那个区间,这个字符串就在这个区间的每个位置上出现,找第 k 小就是静态区间 k 小,套个主席树。

    找区间的时候有点小细节需要注意。

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    typedef long double LD;
    typedef pair<int,int> pii;
    typedef pair<LL,int> pli;
    typedef pair<LL,LL> pll;
    const int SZ = 1e6 + 10;
    const int INF = 1e9 + 10;
    const int mod = 1e9 + 7;
    const LD eps = 1e-8;
    
    LL read() {
        LL n = 0;
        char a = getchar();
        bool flag = 0;
        while(a > '9' || a < '0') { if(a == '-') flag = 1; a = getchar(); }
        while(a <= '9' && a >= '0') { n = n * 10 + a - '0',a = getchar(); }
    	if(flag) n = -n;
    	return n;
    }
    
    struct SuffixArray {
        /// 串从0开始,a[len]是非法字符
        /// sa[i]表示排名为i的后缀 i在[0,len-1]
        /// lcp[i]表示sa[i]和sa[i-1]的lcp i在[1,len-1]
        int lcp[SZ],sa[SZ],rk[SZ],len;
        bool cmp(int *y,int a,int b,int k) {
            int a1 = y[a],b1 = y[b];
            int a2 = a + k >= len ? -1 : y[a + k];
            int b2 = b + k >= len ? -1 : y[b + k];
            return a1 == b1 && a2 == b2;
        }
    
        int t1[SZ],t2[SZ],cc[SZ];
    
        void get_sa(char s[],int m) {
            int *x = t1,*y = t2; /// 字符集
            for(int i = 0;i < m;i ++) cc[i] = 0;
            for(int i = 0;i < len;i ++) ++ cc[x[i] = s[i]];
            for(int i = 1;i < m;i ++) cc[i] += cc[i - 1];
            for(int i = len - 1;~i;i --) sa[-- cc[x[i]]] = i;
            for(int k = 1;k < len;k <<= 1) {
                int p = 0;
                for(int i = len - k;i < len;i ++)  y[p ++] = i;
                for(int i = 0;i < len;i ++) if(sa[i] >= k) y[p ++] = sa[i] - k;
                for(int i = 0;i < m;i ++) cc[i] = 0;
                for(int i = 0;i < len;i ++) ++ cc[x[y[i]]];
                for(int i = 1;i < m;i ++) cc[i] += cc[i - 1];
                for(int i = len - 1;~i;i --) sa[-- cc[x[y[i]]]] = y[i];
                swap(x,y); m = 1; x[sa[0]] = 0;
    
                for(int i = 1;i < len;i ++)
                    x[sa[i]] = cmp(y,sa[i - 1],sa[i],k) ? m - 1 : m ++;
                if(m >= len) break;
            }
        }
    
        void get_lcp(char s[]) {
            for(int i = 0;i < len;i ++) rk[sa[i]] = i;
            int h = 0;
            lcp[0] = 0;
            for(int i = 0;i < len;i ++) {
                if(!rk[i]) continue;
                int j = sa[rk[i] - 1];
                if(h) h --;
                while(s[i + h] == s[j + h]) h ++;
                lcp[rk[i]] = h;
            }
        }
    
        void init(char *s,int n,int m) {
            len = n;
            get_sa(s,m); get_lcp(s);
        }
    }sa;
    
    int st[SZ][22];
    
    void get_st(int a[],int n) {
        for(int i = 1;i <= n;i ++) st[i][0] = a[i];
    
        for(int j = 1;j <= log2(n);j ++) {
            for(int i = 1;i + (1<<j) - 1 <= n;i ++) {
                st[i][j] = min(st[i][j-1],st[i+(1<<(j-1))][j-1]);
            }
        }
    
      /*  for(int i = 1;i <= n;i ++) {
            for(int j = 0;j <= log2(n);j ++) {
                printf("%4d",st[i][j]);
            }
            puts("");
        }*/
    }
    
    int ask_min(int l,int r) {
        int k = log2(r-l+1);
        return min(st[l][k],st[r-(1<<k)+1][k]);
    }
    
    struct seg {
        int l,r,sz;
    }tree[30000010];
    
    int Tcnt = 0,rt[SZ];
    
    void insert(int l,int r,int last,int &now,int v,int x) {
        now = ++ Tcnt;
        tree[now] = tree[last];
        tree[now].sz += x;
        if(l == r) return;
        int mid = (l + r) >> 1;
        if(v <= mid) insert(l,mid,tree[last].l,tree[now].l,v,x);
        else insert(mid + 1,r,tree[last].r,tree[now].r,v,x);
    }
    
    int ask_kth(int l,int r,int k) {
       // printf("[%d,%d] %d
    ",l,r,k);
        if(r-l+1 < k) return -2;
        int L = 0,R = sa.len-1;
        int tl = rt[l-1],tr = rt[r];
        while(L != R) {
            int mid = L + R >> 1;
            int sz = tree[tree[tr].l].sz - tree[tree[tl].l].sz;
            if(sz >= k) {
                tl = tree[tl].l; tr = tree[tr].l; R = mid;
            }
            else {
                tl = tree[tl].r; tr = tree[tr].r; L = mid+1;
                k -= sz;
            }
        }
        return L;
    }
    
    pii ask(int p,int v) {
     //   cout << p << " " <<v << endl;
        pii ans;
        int L,R;
        if(sa.lcp[p] >= v) {
            L = 0,R = p;
            while(R - L > 1) {
                int mid = L + R >> 1;
             //   printf("[%d,%d] min: %d
    ",mid,p,ask_min(mid,p));
                if(ask_min(mid,p) >= v) R = mid;
                else L = mid;
            }
            ans.first = R - 1;
        }
        else ans.first = p;
    
        L = p,R = sa.len;
        while(R - L > 1) {
            int mid = L + R >> 1;
            if(ask_min(p+1,mid) >= v) L = mid;
            else R = mid;
        }
        ans.second = L;
        return ans;
    }
    
    char s[SZ];
    
    int main() {
        int T = read();
        while(T --) {
            int n = read(),m = read();
            scanf("%s",s);
            sa.len = strlen(s);
            sa.get_sa(s,256);
            sa.get_lcp(s);
    /*
            for(int i = 0;i < sa.len;i ++) printf("%3d",i); puts("");
            for(int i = 0;i < sa.len;i ++) printf("%3d",sa.sa[i]); puts("");
            for(int i = 0;i < sa.len;i ++) printf("%3d",sa.lcp[i]); puts("");
            for(int i = 0;i < sa.len;i ++) printf("%3d",sa.rk[i]); puts("");
    */
            Tcnt = 0;
            for(int i = 1;i <= sa.len;i ++) insert(0,sa.len-1,rt[i-1],rt[i],sa.sa[i-1],1);
    
            get_st(sa.lcp,sa.len-1);
    
            while(m --) {
                int l = read(),r = read(),k = read();
                int ll = r - l + 1;
                l --;
                pii qj = ask(sa.rk[l],ll);
                printf("%d
    ",ask_kth(qj.first+1,qj.second+1,k) + 1);
            }
        }
    }
    /**
    233
    5 5
    aabaa
    2 3 1
    
    233
    5 5
    ababc
    1 2 2
    */
    
    

    D

    题意:给一个带权有向图,每次询问第 k 短路径。 (k,n,m,q le 5*10^4)

    key:堆

    一看到 k 很小,就想到每次从堆里拿出来一个拓展,多组询问离线就好了。

    首先把边表按照权值排序,每个状态存 (当前点,当前边表中的第几条边,当前长度) ,每次取出一个,丢进去两个,分别是边表的下一个(如果有的话)和当前点走当前边表的这条边出去的第一条边。复杂度 (O(k log k))

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    typedef long double LD;
    typedef pair<int,int> pii;
    typedef pair<LL,int> pli;
    typedef pair<LL,LL> pll;
    const int SZ = 1e6 + 10;
    const int INF = 1e9 + 10;
    const int mod = 1e9 + 7;
    const LD eps = 1e-8;
    
    LL read() {
        LL n = 0;
        char a = getchar();
        bool flag = 0;
        while(a > '9' || a < '0') { if(a == '-') flag = 1; a = getchar(); }
        while(a <= '9' && a >= '0') { n = n * 10 + a - '0',a = getchar(); }
    	if(flag) n = -n;
    	return n;
    }
    
    vector<pii> g[SZ];
    
    struct haha {
        int u,id;
        LL w;
    };
    
    bool operator <(haha a,haha b) {
        return a.w > b.w;
    }
    
    struct hh {
    
        priority_queue<haha> q;
    
        void push(int u,int id,LL w) {
           // printf("%d %d %lld
    ",u,id,w);
            q.push((haha){u,id,w});
        }
    
        haha top() {
            assert(q.size());
            return q.top();
        }
    
        void pop() {
            assert(q.size());
            haha f = q.top(); q.pop();
         //   printf("%d %d %lld:
    ",f.u,f.id,f.w);
            int u = f.u,v = g[u][f.id].second;
            if(g[v].size()) {
                push(v,0,f.w+g[v][0].first);
            }
    
            f.w -= g[u][f.id].first;
            f.id ++;
            if(f.id < g[u].size())
                f.w += g[u][f.id].first,push(f.u,f.id,f.w);
          //  puts("----------");
        }
    
        void clr() {
            while(q.size()) q.pop();
        }
    }q;
    
    
    LL ans[SZ];
    pii b[SZ];
    
    int main() {
        int T = read();
        while(T --) {
            q.clr();
            int n = read(),m = read(),Q = read();
            for(int i = 1;i <= n;i ++) g[i].clear();
            for(int i = 1;i <= m;i ++) {
                int x = read(),y = read(),w = read();
                g[x].push_back(make_pair(w,y));
            }
            for(int i = 1;i <= n;i ++) sort(g[i].begin(),g[i].end());
    
            for(int i = 1;i <= n;i ++) {
                if(g[i].size())
                    q.push(i,0,g[i][0].first);
            }
            for(int i = 1;i <= Q;i ++) {
                b[i].first = read();
                b[i].second = i;
            }
            sort(b+1,b+1+Q);
            int now = 1;
            for(int i = 1;i <= Q;i ++) {
                while(now < b[i].first) {
                    q.pop();
                    now ++;
                }
                //cout << now << endl;
                haha x = q.top();
                ans[b[i].second] = x.w;
            }
            for(int i = 1;i <= Q;i ++) printf("%lld
    ",ans[i]);
        }
    }
    
    

    E

    题意:给 n,a,b ,计算

    [f(n,a,b)=sum_{i=1}^n sum_{j=1}^i gcd(i^a-j^a,i^b-j^b)[gcd(i,j)=1]\%(10^9+7) ]

    其中 a,b 互质。 (n,a,b le 10^9)

    key:反演

    打表可得,a,b 互质且 i,j 互质时那个 gcd 式子就是 i-j 。

    然后就随便推推,要套个杜教筛

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef long long LL;
    typedef long double LD;
    typedef pair<int,int> pii;
    typedef pair<LL,int> pli;
    typedef pair<LL,LL> pll;
    const int SZ = 5e6 + 10;
    const int INF = 1e9 + 10;
    const int mod = 1e9 + 7;
    const LD eps = 1e-8;
    
    LL read() {
        LL n = 0;
        char a = getchar();
        bool flag = 0;
        while(a > '9' || a < '0') { if(a == '-') flag = 1; a = getchar(); }
        while(a <= '9' && a >= '0') { n = n * 10 + a - '0',a = getchar(); }
    	if(flag) n = -n;
    	return n;
    }
    
    LL ksm(LL a,LL b) {
        LL ans = 1;
        while(b) {
            if(b&1) ans = a * ans;
            a = a * a;
            b >>= 1;
        }
        return ans;
    }
    
    LL ksm(LL a,LL b,LL p) {
        LL ans = 1;
        while(b) {
            if(b&1) ans = a * ans % p;
            a = a * a % p;
            b >>= 1;
        }
        return ans;
    }
    
    const int MAXN = 5e6;
    const int ni2 = (mod+1)/2;
    const int ni6 = ksm(6,mod-2,mod);
    
    bool vis[SZ];
    int pri[SZ],tot,mu[SZ],smud[SZ];
    
    void shai(int n) {
        mu[1] = 1;
        for(int i = 2;i <= n;i ++) {
            if(!vis[i]) pri[++ tot] = i,mu[i] = -1;
            for(int j = 1,m;j <= tot && (m=i*pri[j]) <= n;j ++) {
                vis[m] = 1;
                if(i%pri[j] == 0) {
                    mu[m] = 0;
                    break;
                }
                else {
                    mu[m] = -mu[i];
                }
            }
        }
        for(int i = 1;i <= n;i ++) smud[i] = (smud[i-1] + i * mu[i]) % mod;
    }
    
    LL f1(LL n) {
        n %= mod;
        return n * (n + 1) % mod * ni2 % mod;
    }
    
    LL f2(LL n) {
        n %= mod;
        return n * (n + 1) % mod * (2*n+1) % mod * ni6 % mod;
    }
    
    LL f3(LL n) {
        return f1(n) * f1(n) % mod;;
    }
    
    unordered_map<int,int> smd;
    
    int dfs(int n) {
        if(n <= MAXN) return smud[n];
        if(smd.count(n)) return smd[n];
        LL ans = 1;
        for(int i = 2,r;i <= n;i = r + 1) {
            r = n / (n / i);
            (ans -= dfs(n/i) * (f1(r) - f1(i-1)) % mod) %= mod;
        }
        smd[n] = ans;
        return ans;
    }
    
    
    LL baoli(int n,int a,int b) {
        LL ans = 0;
        for(int i = 1;i <= n;i ++) {
            for(int j = 1;j <= i;j ++) {
                if(__gcd(i,j) == 1) {
                    LL t = __gcd(ksm(i,a)-ksm(j,a),ksm(i,b)-ksm(j,b));
                 //   printf("%d %d %3lld
    ",i,j,t);
                    ans += t;
                }
            }
        }
        return ans;
    }
    
    LL S(LL n) {
        return ni2 * (f2(n) - f1(n)) % mod;
    }
    
    LL work1(int n) {
        LL ans = 0;
        for(int i = 1,r;i <= n;i = r + 1) {
            r = n / (n / i);
            (ans += (dfs(r) - dfs(i-1)) * S(n/i) % mod) %= mod;
        }
        ans += mod; ans %= mod;
        return ans;
    }
    
    
    int main() {
        shai(MAXN);
        int T = read();
        while(T --) {
            int n = read(),a = read(),b = read();
            printf("%lld
    ",work1(n));
        }
    }
    
    

    K

    题意:有一个三维无限大方格平面,每个格点上有权值 1 。修改 m 个形如 (a_{n, x_i, y_i}) 点的点权为 (v_i) 。之后每秒将改 (a_{i,j,k}) 将变为 (a_{i+1,j+p,k} ^ {t1} imes a_{i+1,j,k+q} ^ {t2} imes a_{i+1,j,k} imes a_{i,j,k}) 。求 (n) 秒之后 (a_{0,0,0} mod 998244353) 的值。 (t1,t2,p,q,n le 10^9,m le 10^5)

    key:中国剩余定理,卢卡斯定理

    考虑每个点的贡献。相当于有一个三元组 (x,y,z) ,每次 x 减 1,y 可以不变或者以 t1 的权值减 p,z 可以不变或者以 t2 的权值减 q,一条路径的权值是每步的权值之积。问从 ((x,y,z)) 走到 ((0,0,0)) 的所有路径权值之和,该值作为 (v_i) 的幂次乘给答案。

    实际上一条路径的权值是一定的,所以问题在于求路径条数。这个是 (frac{n!}{a!b!c!}) 的形式。即求 (frac{n!}{a!b!c!} mod (998244353=2^{23} imes 7 imes 17))

    考虑分开,最后 crt 合并。7 和 17 的答案可以直接换成组合数用卢卡斯定理算,现在考虑阶乘模 (2^{23}) 怎么做。由于涉及到求逆,所以要把答案表示成 (n!=A imes 2^B) 的形式。

    (n!=1 imes 2 imes 3 imes 4 imes 5 imes ... imes n = (1 imes 3 imes 5 imes ...) imes 2^{n/2} imes (1 imes 2 imes 3 imes ... imes n/2))

    上面的除都是整除。

    所以就预处理 (1 imes 3 imes 5 imes ...) ,这个显然关于 (2^{22}) 是循环节(因为 (2^{23}+1 mod 2^{23} = 1)),所以就直接递归。

    代码对于 7 和 17 没有用卢卡斯定理,也是用的同样的思路算的阶乘。不过这里要算一个形如 (((p-1)! mod p)^m) 的东西,根据威尔逊定理这东西只与 m 个奇偶性有关,所以可以 (O(1)) 计算,少个 log。

    要 fread 读入优化,hdu卡常。把好多中间变量去掉了居然就过了,神奇……

    #include<bits/stdc++.h>
    using namespace std;
    
    typedef unsigned int UI;
    typedef long long LL;
    typedef long double LD;
    typedef pair<int,int> pii;
    typedef pair<LL,int> pli;
    typedef pair<LL,LL> pll;
    const int SZ = 5e6 + 10;
    const int INF = 1e9 + 10;
    const int mod = 998244353;
    const LD eps = 1e-8;
    
    LL read() {
    	LL n = 0;
    	char a = getchar();
    	bool flag = 0;
    	while(a < '0' || a > '9') { if(a == '-') flag = 1; a = getchar(); }
    	while(a <= '9' && a >= '0') n = n * 10 + a - '0',a = getchar();
    	if(flag) n = -n;
    	return n;
    }
    
    int ksm(int a,int b,int p) {
        int ans = 1;
        while(b) {
            if(b&1) ans = 1ll * a * ans % p;
            a = 1ll * a * a % p;
            b >>= 1;
        }
        return ans;
    }
    
    int pri[] = {2,7,17};
    int pk[] = {8388608,7,17};
    int phi[] = {4194304,6,16};
    
    int fac[8388608+10];
    int fac7[110];
    int fac17[110];
    
    pii f[3][SZ];
    
    const int B = 0;
    
    void pre() {
        int p = 8388608 - 1;
        fac[0] = 1;
        fac[1] = 1;
        for(int i = 3;i <= 8388607;i += 2) {
            fac[i] = (1ll * fac[i-2] * i) & p;
            fac[i-1] = fac[i-2];
        }
        fac7[0] = 1;
        for(int i = 1;i < 7;i ++) fac7[i] = 1ll * fac7[i-1] * i % 7;
        fac17[0] = 1;
        for(int i = 1;i < 17;i ++) fac17[i] = 1ll * fac17[i-1] * i % 17;
    
        for(int i = 0;i < 3;i ++) {
            f[i][0].first = 1;
            for(int j = 1;j <= B;j ++) {
                int x = j,t = 0;
                while(x % pri[i] == 0) x /= pri[i],t ++;
                f[i][j].first = 1ll * f[i][j-1].first * x % pk[i];
                f[i][j].second = f[i][j-1].second + t;
            }
        }
    }
    
    pii dfs(int n,int p) {
        if(n <= B) {
            int id;
            if(p == 7) id = 1;
            else if(p == 17) id = 2;
            else id = 0;
            return f[id][n];
        }
        if(p == 7 || p == 17) {
            if(n < p) {
                return make_pair(p == 7 ? fac7[n] : fac17[n],0);
            }
            pii ans = dfs(n/p,p);
            (ans.first *= (n/p)&1 ? (p == 7 ? fac7[6] : fac17[16]) : 1) %= p;
            ans.first = ans.first * (p == 7 ? fac7[n%p] : fac17[n%p]) % p;
            ans.second += n / p;
            return ans;
        }
        else {
            if(n == 0) return make_pair(1,0);
            if(n == 1) return make_pair(1,0);
            //if(mp.count(make_pair(n,mod))) return mp[make_pair(n,mod)];
            pii ans = dfs(n >> 1,p);
            p --;
            ans.second += n >> 1;
            ans.first = (1ll * ans.first * fac[n & p]) & p;
            return ans;
        }
    }
    
    pii get_fac(int n,int p) {
        pii ans;
        if(p == 7 || p == 17) ans = dfs(n,p);
        else ans = dfs(n,8388608);
        /*int t = 1,mi = 0,mm = p == 2 ? 8388608 : p;
        for(int i = 1;i <= n;i ++) {
            int x = i;
            while(x%p==0) x/=p,mi++;
            t = 1ll * t * x % mm;
        }
        printf("%d! = %lld * %d^%lld
    ",n,ans.first,p,ans.second);
        assert(t == ans.first); assert(mi == ans.second);*/
        return ans;
    }
    
    LL exgcd(LL a,LL b,LL &x,LL &y) {
        if(b == 0) {
            x = 1; y = 0;
            return a;
        }
        LL d = exgcd(b,a%b,x,y);
        LL t = x; x = y; y = t - a / b * y;
        return d;
    }
    
    LL excrt(LL *r,LL *a,int n){ // x%r=a
        LL M=a[1],R=r[1],x,y,d;
        for(int i=2;i<=n;i++){
            d=exgcd(M,a[i],x,y);
            x=(R-r[i])/d * x % a[i];
            R -= M*x;
            M = M/d * a[i];
        }
        return (R%M+M)%M;
    }
    
    int calc(int n,int a,int b,int c) {
        LL r[5],M[5];
        for(int i = 0;i < 3;i ++) {
            pii N = get_fac(n,pri[i]);
            pii A = get_fac(a,pri[i]);
            pii B = get_fac(b,pri[i]);
            pii C = get_fac(c,pri[i]);
            LL ans = 1ll * N.first
                * ksm(A.first,phi[i]-1,pk[i]) % pk[i]
                * ksm(B.first,phi[i]-1,pk[i]) % pk[i]
                * ksm(C.first,phi[i]-1,pk[i]) % pk[i];
            N.second -= A.second;
            N.second -= B.second;
            N.second -= C.second;
            ans = ans * ksm(pri[i],N.second,pk[i]) % pk[i];
            r[i+1] = ans;
            M[i+1] = pk[i];
        }
        return excrt(r,M,3);
    }
    
    struct FastIO{
      static const int S=1310720;
      int wpos,pos,len;char wbuf[S];
      FastIO():wpos(0){}
      inline int xchar(){
        static char buf[S];
        if(pos==len)pos=0,len=fread(buf,1,S,stdin);
        if(pos==len)return -1;
        return buf[pos++];
      }
      inline int xuint(){
        int c=xchar(),x=0;
        while(c<=32&&~c)c=xchar();
        if(c==-1)return -1;
        for(;'0'<=c&&c<='9';c=xchar())x=x*10+c-'0';
        return x;
      }
    }io;
    
    int main() {
      // freopen("1.in","r",stdin);
        //cout << (mod-1) / 2 / 7 * 6 / 17 * 16 << endl;
        pre();
    /*
        int x;
        while(cin >> x) {
            for(int i = 0;i < 3;i ++) {
                get_fac(x,pri[i]);
            }
        }
    */
        int t1,t2,p,q,n,m;
        //while(~scanf("%d%d%d%d%d%d",&t1,&t2,&p,&q,&n,&m)) {
        while(1) {
            t1 = io.xuint();
            if(t1 == -1) break;
            t2 = io.xuint();
            p = io.xuint();
            q = io.xuint();
            n = io.xuint();
            m = io.xuint();
            LL ans = 1;
            for(int i = 1;i <= m;i ++) {
                //int x = read(),y = read(),v = read();
                //int x,y,v; scanf("%d%d%d",&x,&y,&v);
                int x = io.xuint(),y = io.xuint(),v = io.xuint();// scanf("%d%d%d",&x,&y,&v);
                if(x%p) continue;
                if(y%q) continue;
                int a = x / p,b = y / q,c = n - a - b;
                if(c<0) continue;
                int mi = calc(n,a,b,c);
                mi = 1ll * mi * ksm(t1,a,mod-1) % (mod-1) * ksm(t2,b,mod-1) % (mod-1);
            //    cout << mi << endl;
                ans = ans * ksm(v,mi,mod) % mod;
            }
            printf("%lld
    ",ans);
        }
    }
    
    /**
    1 1 1 1000000000 2 6
    0 0 2
    0 1 3
    0 2 4
    1 0 4
    1 1 2
    2 0 2
    
    503044
    */
    
    
  • 相关阅读:
    从例图中学习思维导图的基本概念
    名企面试官精讲典型编程题之C++篇
    PPT,要你好看(全彩)
    文字即艺术
    MindManager中读图工具的使用
    思维导图的三招十八式
    放之四海皆适用的设计原则(一)
    MindManager的例图资源
    内容营销11金规
    专业嵌入式软件开发——全面走向高质高效编程(含DVD光盘1张)
  • 原文地址:https://www.cnblogs.com/dqsssss/p/11403062.html
Copyright © 2020-2023  润新知