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\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网络赛的更多相关文章

  1. CCPC2019网络赛总结

    比赛那会过了两道题,哇贼激动,然后后面就没有然后了... 1003我想到用$kmp$,于是不会$kmp$的我开始找板子套,结果$TLE$,就觉得应该是优化不行,优化后AC妥妥$TLE$,就放弃了. 钓 ...

  2. [CCPC2019网络赛] 1008-Fishing Master(思维)

    >传送门< 题意:现在需要捕$n$条鱼并且将它们煮熟来吃.每条鱼要煮相应的时间才能吃(可以多煮一会),锅里每次只能煮一条鱼,捕一条鱼的时间是相同的,但是在捕鱼的时间内不能做其他事(比如换一 ...

  3. HDU 5875 Function -2016 ICPC 大连赛区网络赛

    题目链接 网络赛的水实在太深,这场居然没出线zzz,差了一点点,看到这道题的的时候就剩半个小时了.上面是官方的题意题解,打完了才知道暴力就可以过,暴力我们当时是想出来了的,如果稍稍再优化一下估计就过了 ...

  4. 大连网络赛 1006 Football Games

    //大连网络赛 1006 // 吐槽:数据比较水.下面代码可以AC // 但是正解好像是:排序后,前i项的和大于等于i*(i-1) #include <bits/stdc++.h> usi ...

  5. 树形DP CCPC网络赛 HDU5834 Magic boy Bi Luo with his excited tree

    // 树形DP CCPC网络赛 HDU5834 Magic boy Bi Luo with his excited tree // 题意:n个点的树,每个节点有权值为正,只能用一次,每条边有负权,可以 ...

  6. (四面体)CCPC网络赛 HDU5839 Special Tetrahedron

    CCPC网络赛 HDU5839 Special Tetrahedron 题意:n个点,选四个出来组成四面体,要符合四面体至少四条边相等,若四条边相等则剩下两条边不相邻,求个数 思路:枚举四面体上一条线 ...

  7. HDU-4041-Eliminate Witches! (11年北京网络赛!!)

    Eliminate Witches! Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Other ...

  8. hihocoder1236(北京网络赛J):scores 分块+bitset

    北京网络赛的题- -.当时没思路,听大神们说是分块+bitset,想了一下发现确实可做,就试了一下,T了好多次终于过了 题意: 初始有n个人,每个人有五种能力值,现在有q个查询,每次查询给五个数代表查 ...

  9. 36th成都区域赛网络赛 hdoj4039 The Social Network(建图+字符串处理)

    这题是某年成都区域赛网络赛的一题. 这题思路非常easy,可是从时间上考虑,不妨不要用矩阵存储,我用的链式前向星. 採用线上查询.利用map对字符串编号,由于非常方便.要推荐的朋友,事实上就是朋友的朋 ...

随机推荐

  1. JAVA基本数据类型和注释

    一.注释 1.注释的概念 注释是程序中给人看的提示信息,会被编译器忽略:在程序编译和执行过程中不会有任何影响,仅仅在代码阅读时提供提示信息. 2.注释的形式 基本语法://注释的内容   a.行注释 ...

  2. 苏州大学ICPC集训队新生赛第二场

    A - Score UVA - 1585 水 #include<bits/stdc++.h> using namespace std; int main(){ int n; cin> ...

  3. HDU - 5976 Detachment(逆元)

    题意:将一个数x拆成a1+a2+a3+……,ai不等于aj,求最大的a1*a2*a3*……. 分析: 1.预处理前缀和前缀积,因为拆成1对乘积没有贡献,所以从2开始拆起. 2.找到一个id,使得2+3 ...

  4. c++ 字符串转数字或数字转字符串

    在C++中字符串转换为数字,或数字转换为字符串,用到如下函数: _itoa atoi.atof.itoa.itow _itoa_s 1.整形转换为字符串: wchar_t * _itot(int _V ...

  5. EUI库 - 9 - 数据集合 - 数据容器

      DataGroup 设置一个数据源 自动创建内部所需的对象 来完成数据展示   还要设置单条数据的模板  叫ItemRenderer   继承关系 eui.List  eui.ListBase e ...

  6. C++编程学习(一) 概述

    从一年前开通博客,陆陆续续写了一些总结类的东西,但是一直没push到网上.现在发现,分享自己的笔记也是自身学习.与他人交流的好方式.从今天开始,我会经常的push一些学习笔记到博客中,先从C++开始吧 ...

  7. 关于Pytorch中autograd和backward的一些笔记

    参考自<Pytorch autograd,backward详解>: 1 Tensor Pytorch中所有的计算其实都可以回归到Tensor上,所以有必要重新认识一下Tensor. 如果我 ...

  8. Zookeeper--Zookeeper单机安装

    参考 https://www.cnblogs.com/lsdb/p/7297731.html https://zookeeper.apache.org/doc/r3.4.13/zookeeperSta ...

  9. Java实用小工具

    工具一:对Java中的List<Map<String,Object>>格式数据实现递归 /** * 递归List<Map<String,Object>> ...

  10. vector删除指定元素

    #pragma once #include "stdafx.h" #include<windows.h> #include <vector> #includ ...