LightOJ

题意:http://www.lightoj.com/volume_showproblem.php?problem=1117

考虑1个数k,1~n有[n/k]个数能被k整除,[a]表示a向下取整,

所以ans= n-SIGMA([n/num[i]])(1<=i<=m)。再考虑2个数a,b,因为被a整除同时被b整除这部分减了两次,

所以要加上,ans += n/lcm(a,b),枚举2个数,又发现3个数的多加了,再减去3个的,再加上4个的,减去5个的,以此类推。

比如m=4

我们就有2的4次方减一 也就是15种方法   可以为二进制的1111 正好对应这m  所以将每一个都便利

然后就是奇数加  偶数减   求出m个数在【1-n】中有多少个倍数

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<vector>
#include<math.h>
#include<string>
using namespace std;
#define INF 0x3f3f3f3f
#define LL long long
#define N 106
#define Lson rood<<1
#define Rson rood<<1|1
int a[N];
LL gcd(LL a,LL b)
{
    return b==0?a:gcd(b,a%b);
}
int main()
{
    int T,t=1;
    scanf("%d",&T);
    while(T--)
    {
        LL n,m,sum=0,ans=0;
        scanf("%lld%lld",&n,&m);
        for(int i=0;i<m;i++)///状态压缩
            scanf("%lld",&a[i]);
        for(int i=1;i<(1<<m);i++)
        {
            LL ans=1;
            int t=0;///将为一种情况都遍历出来
            for(int j=0;(1<<j)<=i;j++)
            {
                if(1<<j&i)
                {
                    t++;
                    ans=ans*a[j]/gcd(ans,a[j]);
                }
            }///根据公式  奇数加  偶数减
            if(t%2) sum+=n/ans;
            else sum-=n/ans;
        }///sum保存的是在n中有多少个(m个数的倍数)
        printf("Case %d: %lld
",t++,n-sum);
    }
    return 0;
}

  

原文地址:https://www.cnblogs.com/a719525932/p/7699522.html