在学校熬夜打$cf$找死啊。
A - Enlarge GCD
先求个$gcd$,每个$a[i]$都除以$gcd$。
之后枚举每个质数看可以整除的数的个数即可。证明显然。
#include <bits/stdc++.h> #define min(a,b) ((a)<(b)?(a):(b)) #define max(a,b) ((a)>(b)?(a):(b)) #define for1(a,b,i) for(int i=a;i<=b;++i) #define FOR2(a,b,i) for(int i=a;i>=b;--i) using namespace std; typedef long long ll; inline int read() { int f=1,sum=0; char x=getchar(); for(;(x<'0'||x>'9');x=getchar()) if(x=='-') f=-1; for(;x>='0'&&x<='9';x=getchar()) sum=sum*10+x-'0'; return f*sum; } #define M 1000005 #define N 15000000 int n; int a[M],f[M*20],prime[N+5]; bool notprime[N+5]; inline bool check(int x) { for1(1,n,i) if(x!=a[i]) return 0; return 1; } inline int gcd(int x,int y) {return y?gcd(y,x%y):x;} inline void get_prime() { for1(2,N,i) { if(!notprime[i]) prime[++prime[0]]=i; for1(1,prime[0],j) { if(i*prime[j]>N) break; notprime[i*prime[j]]=1; if(!(i%prime[j])) break; } } } int main() { //freopen("a.in","r",stdin); //freopen("mine.out","w",stdout); get_prime(); n=read(); for1(1,n,i) a[i]=read(); int sum=a[1]; for1(2,n,i) sum=gcd(sum,a[i]); if(check(sum)) return puts("-1"),0; int Max=0; for1(1,n,i) { a[i]/=sum,++f[a[i]]; Max=max(Max,a[i]); } int ans=0; for1(2,Max,i) { if(notprime[i]) continue; int x=i; int tot=0; while (x<=Max) tot+=f[x],x+=i; ans=max(ans,tot); } cout<<n-ans<<endl; }
B - Little C Loves 3 II
做这种题我一直都是完蛋。
不想找一个规律,但是自己又不能证明。
主要就是$nm$都很大的时候都可以填到最满,然后特判几个不满足的。
#include <bits/stdc++.h> #define for1(a,b,i) for(int i=a;i<=b;++i) #define FOR2(a,b,i) for(int i=a;i>=b;--i) using namespace std; typedef long long ll; int main() { //freopen("a.in","r",stdin); ll n,m; cin>>n>>m; if(n>m) swap(n,m); ll ans=0; if(n==1) ans=m/6*6+max(0ll,m%6-3)*2; else if(n==2) { ans=n*m; if(m==2) ans=0; if(m==3||m==7) ans-=2; } else ans=n*m-(n*m&1); cout<<ans<<endl; }
$C. Region Separation$
显然对于每一种$val$的划分只有一种方案。
并且如果可以划分成$x$块和$d$块,且$d|x$,那么一定$d$是可以作为$x$的下一级的。
难点就在于我们怎么判断分成$x$块是否可行。
设$sum[i]$为$i$的子树的权值和。
条件:有$x$个点满足$sum[i]%(sum[1]/x)==0$。
因为我们划分之后的方案也可以表示成一棵树。
且其中每个点都是原树上的一个联通块,且权值为$sum[1]/x$。
然后就可以$O(n*logn)$了。
#include <bits/stdc++.h> #define for1(a,b,i) for(int i=a;i<=b;++i) #define FOR2(a,b,i) for(int i=a;i>=b;--i) using namespace std; typedef long long ll; #define M 1000005 #define mod 1000000007 int n; ll val[M]; int fa[M],vis[M],f[M]; inline ll gcd(ll x,ll y) {return y?gcd(y,x%y):x;} inline void inc(int &x,int y) {x+=y,x-=x>=mod?mod:0;} int main () { //freopen("a.in","r",stdin); scanf("%d",&n); for1(1,n,i) scanf("%lld",val+i); for1(2,n,i) scanf("%d",fa+i); FOR2(n,2,i) val[fa[i]]+=val[i]; for1(1,n,i) { ll d=val[1]/gcd(val[i],val[1]); if (d<=n) ++vis[d]; } FOR2(n,1,i) { if(vis[i]) for(int j=2*i;j<=n;j+=i) vis[j]+=vis[i]; } FOR2(n,1,i) { if(vis[i]!=i) continue; f[i]=1; for(int j=2*i;j<=n;j+=i) inc(f[i],f[j]); } printf("%d\n",f[1]); }
$D. Intervals of Intervals$