dlutoj 1411 Measuring Cylinder(二分+容斥)

来源:互联网 发布:知乎产品分析报告 编辑:程序博客网 时间:2024/04/30 13:24

这是我们周日埃森哲的一个题,这题还不错,有点意思的。
题意就是给你n个量杯,然后你可以给量杯倒满水,倒来倒去,最后要求你得到1单位量的水,最少需要选择几个杯子。
看到这里就想到了就是给你一堆数字,然后减来减去,最后得到1,这个就是扩展欧几里德的推广了,就是这些数字的gcd=1的话,就是他们可以最后得到1.
想到了这里才是刚刚开始呢,这题要求最少需要几个杯子,这就有点难办了,很难直接算出来需要几个杯子,所以可以转换一下思路,如果你知道需要几个杯子,能否求出他们是否能够得到gcd=1,这就等于求gcd=1的方案数是不是0。
因为是求杯子的最少个数,所以我们可以直接二分答案,然后去求n个数中取了x个数,能得到gcd=1的方案数是多少。
这个就是个老问题了啊,容斥呗,首先求出bei[i]表示i的倍数有多少个,f[i]表示gcd为i的倍数的方案数,g[i]表示gcd为i的方案数。
所以可以得到

f[i]=C(bei[i],x)
g[i]=g[i]g[i]g[2i]g[3i]g[ki]
bei[i]可以输入的时候记录,然后筛法求出,f[i]通过组合数逆元求出,g[i]也是通过筛法,而且要倒着枚举i


代码

#include <map>#include <set>#include <stack>#include <queue>#include <cmath>#include <string>#include <vector>#include <cstdio>#include <cctype>#include <cstring>#include <sstream>#include <cstdlib>#include <iostream>#include <algorithm>#pragma comment(linker, "/STACK:102400000,102400000")using namespace std;#define   MAX           100005#define   MAXN          6005#define   maxnode       15#define   sigma_size    30#define   lson          l,m,rt<<1#define   rson          m+1,r,rt<<1|1#define   lrt           rt<<1#define   rrt           rt<<1|1#define   middle        int m=(r+l)>>1#define   LL            long long#define   ull           unsigned long long#define   mem(x,v)      memset(x,v,sizeof(x))#define   lowbit(x)     (x&-x)#define   pii           pair<int,int>#define   bits(a)       __builtin_popcount(a)#define   mk            make_pair#define   limit         10000//const int    prime = 999983;const int    INF   = 0x3f3f3f3f;const LL     INFF  = 0x3f3f;const double pi    = acos(-1.0);//const double inf   = 1e18;const double eps   = 1e-8;const LL    mod    = 1e9+7;const ull    mx    = 133333331;/*****************************************************/inline void RI(int &x) {      char c;      while((c=getchar())<'0' || c>'9');      x=c-'0';      while((c=getchar())>='0' && c<='9') x=(x<<3)+(x<<1)+c-'0'; }/*****************************************************/int a[MAX];int bei[MAX];LL cnt[MAX];LL f[MAX];int n;LL fact[MAX];int maxn;int gcd(int a,int b){    if(!b) return a;    return gcd(b,a%b);}LL qpow(LL a,LL n){    LL ans=1;    while(n){        if(n&1) ans=ans*a%mod;        a=a*a%mod;        n>>=1;    }    return ans;}LL C(int a,int b){    if(a<b) return 0;    return (fact[a]*qpow(fact[b],mod-2)%mod)*qpow(fact[a-b],mod-2)%mod;}bool check(int x){    for(int i=1;i<=maxn;i++){        cnt[i]=C(bei[i],x);    }    for(int i=maxn;i>0;i--){        f[i]=cnt[i];        for(int j=2*i;j<=maxn;j+=i) f[i]-=f[j];        f[i]=(f[i]%mod+mod)%mod;    }    if(f[1]>0) return true;    return false;}void init(){    fact[0]=1;    for(int i=1;i<=100000;i++) fact[i]=fact[i-1]*i%mod;}int main(){    int t;    cin>>t;    init();    while(t--){        cin>>n;        mem(bei,0);        int tmp=0;        maxn=0;        for(int i=1;i<=n;i++){            scanf("%d",&a[i]);            tmp=gcd(tmp,a[i]);            maxn=max(maxn,a[i]);            bei[a[i]]++;        }        for(int i=1;i<=maxn;i++){            for(int j=2*i;j<=maxn;j+=i) bei[i]+=bei[j];            //if(bei[i]) cout<<bei[i]<<" "<<i<<endl;        }        if(tmp!=1) printf("-1\n");        else{            int l=1,r=n;            while(l<=r){                int mid=(l+r)/2;                if(check(mid)) r=mid-1;                else l=mid+1;            }            cout<<l<<endl;        }    }    return 0;}/**************************************************************    Problem: 1411    User: 1403mashaonan    Language: C++    Result: Accepted    Time:5592 ms    Memory:4776 kb****************************************************************/
0 0
原创粉丝点击