Codeforces1047
A.Little C Loves 3 I
题意:给定一个整数N,问是否存在整数a b c使得a+b+c=N且a b c均不为3的倍数
题解:考虑到mod3的余数只有0 1 2,所以直接取1,1,N-2 或 1,2,N-3 或 2,2,N-4
代码:
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; int N; int main(){ cin >> N; if((N-2)%3) cout << 1 << ' ' << 1 << ' ' << N-2 << endl; else if((N-3)%3) cout << 1 << ' ' << 2 << ' ' << N-3 << endl; else cout << 2 << ' ' << 2 << ' ' << N-4 << endl; return 0; }
B.Cover Points
题意:给定平面上N个第一象限内的整数点,求一条斜率为-1的直线,使得所有点都在这条直线的下方
题解:找截距最大的就行
代码:
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; int Ans,N; int main(){ cin >> N; for(int i=1,x,y;i<=N;i++){ cin >> x >> y; Ans=max(Ans,x+y); } cout << Ans << endl; return 0; }
C.Enlarge GCD
题意:给定N个数,求删除最少的数,使得剩余数的最大公约数严格大于原来的最大公约数
题解:先把所有的数除以最大公约数,则问题转化为求最大公因数不为1的最多的个数。枚举因子,统计答案。
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; const int MAXN=300000+2; const int MAXM=15000000+2; int a[MAXN],N,g,c[MAXM],Ans,U; bool Flag[MAXM]; int gcd(int a,int b){ if(a<b) swap(a,b); return b?gcd(b,a%b):a; } int main(){ cin >> N; for(int i=1;i<=N;i++){ cin >> a[i]; g=(g?gcd(g,a[i]):a[i]); } for(int i=1;i<=N;i++) a[i]/=g,c[a[i]]++,U=max(U,a[i]); for(int i=2,S=0;i<=U;i++,S=0){ if(!Flag[i]) for(int j=i;j<=U;j+=i) S+=c[j],Flag[j]=1; Ans=max(Ans,S); } cout << (Ans?N-Ans:-1) << endl; return 0; }
D.Little C Loves 3 II
题意:在一个网格图上放尽量多的点对,使得每个点对的曼哈顿距离均为3
题解:假设N<M,先特判掉N==1的情况,然后可以发现N=2时,只有M=2 3 7无法完全放满;N=3时,都可以放满。因此对于更大的N,可以直接拆成2和3的和。
代码:
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; #define ll long long ll N,M; int main(){ cin >> N >> M; if(N>M) swap(N,M); if(N==1){ if(M%6==0) cout << M << endl; else if(M%6<=3) cout << M-(M%6) << endl; else cout << M-(6-M%6) << endl; } else if(N==2 && M==2) cout << 0 << endl; else if(N==2 && M==3) cout << 4 << endl; else if(N==2 && M==7) cout << 12 << endl; else{ if((N&1) && (M&1)) cout << N*M-1 << endl; else cout << N*M << endl; } return 0; }
E.Region Separation
题意:给定一颗点权树,每次可以删除任意数量的边,求每个联通块的点权和相同的切割方案。
题解:挺神的一道题,看了题解才会……假定限制了联通块的数量k,令t=整棵树的点权和/k,那么一个子树的点权和x对答案有贡献当且仅当t|x,即(S/gcd(S,x))|k,那么我们按照k分类求合法子树的数量。记c[k]表示树中点权和x满足:S/gcd(S,x)为k的因子的子树的数量(即其对k的答案有贡献),假如c[i]>=i,那么就存在分成i份的合法方案,统计之。
代码:
#include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> using namespace std; #define ll long long const int MAXN=1000000+2; const ll MOD=1e9+7; int N,p[MAXN]; ll s[MAXN],c[MAXN],f[MAXN],Ans; ll gcd(ll a,ll b){ if(a<b) swap(a,b); return b?gcd(b,a%b):a; } int main(){ cin >> N; for(int i=1;i<=N;i++) scanf("%lld",s+i); for(int i=2;i<=N;i++) scanf("%d",p+i); for(int i=N;i;i--) s[p[i]]+=s[i]; for(int i=N;i;i--){ s[i]=s[1]/gcd(s[1],s[i]); if(s[i]<=N) c[s[i]]++; } for(int i=N;i;i--) for(int j=2*i;j<=N;j+=i) c[j]=(c[j]+c[i])%MOD; f[1]=1; for(int i=1;i<=N;i++) if(c[i]>=i) for(int j=2*i;j<=N;j+=i) f[j]=(f[j]+f[i])%MOD; for(int i=1;i<=N;i++) if(c[i]>=i) Ans=(Ans+f[i])%MOD; cout << Ans << endl; return 0; }