2018 Multi-University Training Contest 7
dls真厉害,快速求$\sum_{a=1}^n \sum_{b=1}^m gcd(a,b) $的个数,我想的方法是根据上节课dls讲的方法,要容过来容过去,这次不用了。
则$f[d]=(n/d)\times (m/d)$。
而$g[d]=f[d]-\sum_{d|x} g[x]$,从大到小枚举因子就可以了。
#include <bits/stdc++.h> using namespace std; const int maxn = 1e6 + 50; typedef long long ll; bool flag[maxn]; //标记数组 ll phi[maxn]; //欧拉函数值 int prime[maxn]; //同时得到素数筛 int cnt = 0; void Get_phi(int n) { cnt = 0; memset(flag,true,sizeof(flag)); phi[1] = 1; for(int i=2;i<=n;i++) { if(flag[i]) //素数 { prime[cnt++] = i; phi[i] = i-1; //素数的欧拉函数值是i-1 } for(int j=0;j<cnt;j++) { if(i*prime[j]>n) { break; } flag[i*prime[j]] = false;//素数的倍数不是素数 if(i%prime[j]==0) //i%mod prime = 0,那么phi(i*p) = p*phi(i) { phi[i*prime[j]] = prime[j]*phi[i]; break; } else phi[i*prime[j]] = (prime[j]-1)*phi[i];//i mod prime != 0, 那么 phi(i * prime) == phi(i) * (prime-1) } } } int inv[maxn]; ll f[maxn]; int main() { int T; scanf("%d", &T); Get_phi(1e6 + 10); while(T--) { int n, m, mod; scanf("%d %d %d", &n, &m, &mod); if(n > m) swap(n, m); inv[0] = inv[1] = 1; for(int i = 2; i <= n; i++) { inv[i] = (ll)(mod - mod / i) * inv[mod % i] % (ll)mod; } ll ans = 0; for(int i = n; i >= 1; i--) ///枚举 d | (a, b) { f[i] = (ll)n / i * (m / i); for(int j = i + i; j <= n; j += i) ///枚举 能够整除d的 { f[i] = f[i] - f[j]; } ans = (ans + f[i] * i % mod * inv[phi[i]]) % mod; //printf("%d %lld phi = %lld %lld\n", i, f[i], phi[i], ans); } printf("%lld\n", ans); } return 0; }
读入挂真的吓人,砍掉了$2/3$的时间。
#include <bits/stdc++.h> using namespace std; const int maxn = 1e5 + 50; inline char nc(){ static char buf[100000],*p1=buf,*p2=buf; return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++; } inline int _read(){ char ch=nc();int sum=0; while(!(ch>='0'&&ch<='9'))ch=nc(); while(ch>='0'&&ch<='9')sum=sum*10+ch-48,ch=nc(); return sum; } struct node { int a[6]; int b[6]; }; node cur[maxn]; struct single { int val, id; friend bool operator < (single A, single B) { return A.val > B.val; } }; priority_queue<single> q[6]; int v[6]; int main() { int T; T = _read(); while(T--) { int n, k; n = _read(), k = _read(); // printf("%d %d\n", n, k); for(int i = 1; i <= k; i++) v[i] = _read(); for(int i = 1; i <= k; i++) { while(!q[i].empty()) q[i].pop(); } for(int i = 1; i <= n; i++) { for(int j = 1; j <= k; j++) cur[i].a[j] = _read(); for(int j = 1; j <= k; j++) cur[i].b[j] = _read(); q[1].push({cur[i].a[1], i}); } int flag = 0; int ans = 0; while(1) { flag = 0; for(int i = 1; i <= k; i++) { if(q[i].empty()) continue; single tmp = q[i].top(); if(tmp.val <= v[i]) { flag = 1; q[i].pop(); if(i == k) { ans++; for(int j = 1; j <= k; j++) { v[j] += cur[tmp.id].b[j]; } } else { q[i + 1].push({cur[tmp.id].a[i + 1], tmp.id}); } } } if(!flag) break; } printf("%d\n", ans); for(int i = 1; i <= k; i++) { printf("%d%c", v[i], i < k ? ' ' : '\n'); } } return 0; }