2020牛客多校第四场BFH题解
B. Basic Gcd Problem
找规律签到,易发现结果就是c的【n的质因数的个数】次方再mod 1e9+7。快速幂解决。
F. Finding the Order
签到。给定AC,AD,BC,BD四个点的距离,问是AB//CD还是AB//DC。
我的方法,固定AB及其中垂线位置。判断C在AB左方还是右方,之后根据BC和BD关系判断D在C的哪个方向。
#include <bits/stdc++.h> using namespace std; int main() { int t; cin >> t; while(t--) { int AC,AD,BC,BD; cin>>AC>>AD>>BC>>BD; int ans=0; if(AC<BC) { if(AD<BD) { if(BC>BD) ans=1; else ans=0; } else ans=1; } else if(AC==BC) { if(AD>BD) ans=1; } else { if(AD>BD && AC<AD) ans=1; } if(ans) puts("AB//CD"); else puts("AB//DC"); } }
还有很多种方法,这里列出大佬们的一个简洁代码。
#include <cstdio> int T,a,b,c,d; int main(){ scanf("%d",&T); while(T--){ scanf("%d%d%d%d",&a,&b,&c,&d); puts(b+c>a+d?"AB//CD":"AB//DC"); } }
H. Harder Gcd Problem
题意
• 把 1~N 的数选尽量多的组,使得每组 gcd 大于 1。
• 输出任意一种方案。
题解
• 2p>n 的 p 必然不能匹配,将它们除去。
• 倒序枚举所有质因子 p,考虑所有是 p 的倍数且未被匹配的数,任意将它们进行匹配。
• 如果个数是奇数就不选 p*2。(尽量贪心地保证不选的数之后还能得到匹配)
#include <bits/stdc++.h> #define show(x) std::cerr << #x << "=" << x << std::endl using namespace std; const int maxn = 1e6 + 5; int v[maxn], prime[maxn], ans[maxn]; bool vis[maxn]; int m, n; void primes(int n) { //素数线性筛 memset(v,0,sizeof(v)); m = 0; for(int i = 2; i <= n; i++) { if(v[i] == 0) { v[i] = i; prime[++m] = i; } for(int j = 1; j <= m; j++) { if(prime[j] > v[i] || prime[j] > n/i) break; v[i * prime[j]] = prime[j]; } } // for(int i = 1; i <= m; i++) { // printf("%d ",prime[i]); // mp[prime[i]] ++; // } } int main() { primes(2e5+100); int t; scanf("%d",&t); while(t--) { scanf("%d",&n); memset(ans, 0, sizeof(ans)); memset(vis, 0, sizeof(vis)); int id = 0; int pos = upper_bound(prime+1, prime+m+1, n/2) - prime - 1; // show(pos); for(int i=pos; i>0; i--) { for(int j=prime[i]; j<=n; j+=prime[i]) { if(vis[j] || j == (prime[i]<<1)) continue; // 特判2p,最后加入 ans[id++] = j; vis[j]++; } if(id&1) ans[id++]=(prime[i]<<1), vis[ans[id-1]]++; } printf("%d\n",id/2); for(int i=0; i<id; i+=2) { printf("%d %d\n", ans[i], ans[i+1]); } } }