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\) 的幂次乘给答案。
实际上一条路径的权值是一定的,所以问题在于求路径条数。这个是 \(\frac{n!}{a!b!c!}\) 的形式。即求 \(\frac{n!}{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,typedef,const,10,int,LL,网络,sa 来源: https://www.cnblogs.com/dqsssss/p/11403062.html