CCPC2019网络赛

Posted dqsssss

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CCPC2019网络赛相关的知识,希望对你有一定的参考价值。

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

A

题意:找到最小的正整数 C 使得 (A^C)&(B^C) 最小。 \(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\n",max(1ll,n&m));
    

B

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

key:线段树

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

由于线段树自带二分性,所以可以直接找,复杂度 \(O(n\log 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\n",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\n",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\n",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\n",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\n",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\n",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\n",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:\n",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\n",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\n",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\n",work1(n));
    

K

题意:有一个三维无限大方格平面,每个格点上有权值 1 。修改 m 个形如 \(a_n, x_i, y_i\) 点的点权为 \(v_i\) 。之后每秒将改 \(a_i,j,k\) 将变为 \(a_i+1,j+p,k ^ t1 \times a_i+1,j,k+q ^ t2 \times a_i+1,j,k \times a_i,j,k\) 。求 \(n\) 秒之后 \(a_0,0,0 \bmod 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\) 的幂次乘给答案。

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

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

\(n!=1\times 2 \times 3 \times 4 \times 5 \times ... \times n = (1 \times 3 \times 5 \times ...) \times 2^n/2 \times (1 \times 2 \times 3 \times ... \times n/2)\)

上面的除都是整除。

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

代码对于 7 和 17 没有用卢卡斯定理,也是用的同样的思路算的阶乘。不过这里要算一个形如 \(((p-1)! \bmod 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",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\n",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
*/

以上是关于CCPC2019网络赛的主要内容,如果未能解决你的问题,请参考以下文章

CCPC2019网络赛

CCPC2019网络赛总结

2019杭电多校&CCPC网络赛&大一总结

HDU6706 CCPC 2019网络赛 huntian oy 推式子+杜教筛

2019CCPC网络赛 HDU 6702——找规律

CCPC 2019 网络赛 1002 array (权值线段树)