HPUOJ WitchMirror 【容斥】or 【状态压缩+容斥】

来源:互联网 发布:数据库的事务是什么 编辑:程序博客网 时间:2024/06/06 19:50

王炸的队友地雷(你可以叫他雷雷)要考科一了,但地雷总是不太自信,因为他看的题太少了。

王炸为了帮他,就拿出来了一面魔镜,这个魔镜可以告诉雷雷他还不会的题有多少。但是魔镜自诩是hpu毕业的高材生,并不想直接了当的告诉地雷,他通过以下这种方式让地雷自己计算出来:

魔镜给地雷m个数字(a1、a2 …… am)和一个整数n,魔镜定义:如果有一个数,是这m个数字里面任意一个数的倍数,那么这个数称为LuckyNumber。而雷雷会的题数为[1,n]闭区间内LuckyNumber的数量。

那么请你帮地雷计算一下他会的题目数。

输入
有多组数据,每组数据第一行给出两个字母n、m,含义如题意所示。

数据第二行给出m个整数:a1、a2 …… am。

(1≤ n、a1、a2 …… am ≤ 1e9,1 ≤ m ≤ 15 )

输出
输出一个整数,表示地雷会的题目数。

样例输入
10 2
5 7
100 1
1
样例输出
3
100

代码
// 56ms ac

#include<bits/stdc++.h>#define LL long longusing namespace std;const int MAXN = 1e5;const int MAXM = 3000000;const int inf = 0x3f3f3f3f;const double eps = 1e-8 ;/*------------------------------*/LL gcd(LL a,LL b){    return b==0?a:gcd(b,a%b);}LL lcm(LL a,LL b){    return a/gcd(a,b)*b;}LL p[20];LL ge;LL nop(LL m){    LL que[MAXN];    LL top=0;    que[top++]=-1;    for(int i=0;i<ge;i++){        LL temp=top;        for(int j=0;j<temp;j++){ // 这里也是控制了 奇加偶减。            LL f=1;            if(que[j]<0) f=-1;            que[top++]=f*lcm(abs(que[j]),p[i])*(-1);        }    }    LL sum=0;    for(LL i=1;i<top;i++){        sum+=m/que[i];    }    return sum;}int main(){    LL m;  LL n;    while(~scanf("%lld%lld",&n,&m)){        for(int i=0;i<m;i++) scanf("%lld",&p[i]);            ge=m;        printf("%lld\n",nop(n));    }    return 0;}

2017 11 3
今天又做到一个容斥,用了状态压缩的姿势来枚举所有的情况,感觉很棒。 学习一下。

/ / 重复算了好多 gcd 和lcm 导致慢了好多 200+ms

#include<bits/stdc++.h>using namespace std;typedef pair<int,int>pii;#define first fi#define second se#define  LL long long#define fread() freopen("in.txt","r",stdin)#define fwrite() freopen("out.txt","w",stdout)#define CLOSE() ios_base::sync_with_stdio(false)const int MAXN = 30;const int MAXM = 1e6;const int mod = 1e9+7;const int inf = 0x3f3f3f3f;LL gcd(LL a,LL b){    return b==0?a:gcd(b,a%b);}LL lcm(LL a,LL b){    return a/gcd(a,b)*b;}LL a[MAXN];int main(){    CLOSE();//  fread();//  fwrite();    LL n,m;    while(scanf("%lld%lld",&n,&m)!=EOF){        for(int i=0;i<m;i++) scanf("%lld",&a[i]);        LL ans=0;        for(int i=1;i<(1<<m);i++){  //            int cnt=0;  LL LCM = 1;             for(int j=0;j<m;j++){                if(1&(i>>j)) {                    cnt++;                    LCM=lcm(LCM,a[j]);                 }             }             if(cnt&1) ans+=n/LCM;// 奇加偶减             else ans-=n/LCM;         }         printf("%lld\n",ans);     }}
原创粉丝点击