hdoj-1796-How many integers can you find

来源:互联网 发布:塞班3软件下载 编辑:程序博客网 时间:2024/06/05 02:16

Description

  Now you get a number N, and a M-integers set, you should find out how many integers which are small than N, that they can divided exactly by any integers in the set. For example, N=12, and M-integer set is {2,3}, so there is another set {2,3,4,6,8,9,10}, all the integers of the set can be divided exactly by 2 or 3. As a result, you just output the number 7.
 

Input

  There are a lot of cases. For each case, the first line contains two integers N and M. The follow line contains the M integers, and all of them are different from each other. 0<N<2^31,0<M<=10, and the M integer are non-negative and won’t exceed 20.
 

Output

  For each case, output the number.
 

Sample Input

12 22 3
 

Sample Output

7
 
#include<iostream>#include<cstdio>#include<iostream>#include<algorithm>#define ll long longusing namespace std;ll n,m,a[12],ans,p;ll gcd(ll a,ll b){        if (!b) return a;        return gcd(b,a%b);}void DFS(ll i,ll w,ll k){        for (;i<=n;i++)        if (a[i])        {            p=a[i]*w/gcd(a[i],w);            ans+=k*(m/p);            DFS(i+1,p,-k);        }        return;}int main(){        ll i;        while (cin>>m>>n)        {                for (i=1;i<=n;i++) cin>>a[i];                ans=0;                m--;                DFS(1,1,1);                cout<<ans<<endl;        }        return 0;}



给定n和一个大小为m的集合,集合元素为非负整数。为1…n内能被集合里任意一个数整除的数字个数。n<=2^31,m<=10。

数据范围比较大,暴力去找肯定超时,2^31数组也存不了容斥原理地简单应用。先找出1…n内能被集合中任意一个元素整除的个数,再减去能被集合中任意两个整除的个数,即能被它们两只的最小公倍数整除的个数,因为这部分被计算了两次,然后又加上三个时候的个数,然后又减去四个时候的倍数…所以深搜,最后判断下集合元素的个数为奇还是偶,奇加偶减。


另外加一种2进制的做法,具体模板在挑战程序设计的p297

#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;typedef long long ll;const int maxn=15;ll a[maxn];ll n,m;ll gcd(ll a,ll b){        if (!b) return a;        return gcd(b,a%b);}void solve(){    ll res=0;    for(ll i=1;i<(1<<m);i++)    {        ll num=0;        for(ll j=i;j!=0;j>>=1) num+=j&1;        ll lcm=1;        for(ll j=0;j<m;j++){            if(i>>j&1){                lcm=lcm*a[j]/gcd(lcm,a[j]);                if(lcm>n)  break;            }        }        if(num%2==0) res-=n/lcm;        else res+=n/lcm;    }    printf("%lld\n",res);}int main(){    while(scanf("%lld%lld",&n,&m)!=EOF)    {        n--;        for(ll i=0;i<m;i++)        {            scanf("%lld",&a[i]);            if(a[i]<1||a[i]>=n)                {                m--;                i--;                }        }        solve();    }    return 0;}

这道题有个wa点就是需要对输出的数的范围判断,否则会RE

0 0
原创粉丝点击