Codeforces Round #511 (Div. 1) 题解

在学校熬夜打$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$

猜你喜欢

转载自www.cnblogs.com/asd123www/p/9758521.html