How many integers can you find
Time Limit: 12000/5000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 3315 Accepted Submission(s): 937
Problem 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 2 2 3
Sample Output
7
原理:首先考虑一个问题,1000以内6,7,8,9的倍数有多少个?答案是
1000div6+1000div7+1000div8+1000div9
-1000div(6*7)-1000div(6*8)-1000div(6*9)-1000div(7*8)-1000div(7*9)-1000div(8*9)
+1000div(6*7*8)+1000div(6*8*9)+1000div(7*8*9)+1000div(6*7*9)
-1000div(6*7*8*9)
以一个数6为例说一下下面的深搜思想
6,lcm=1,k=1->lcm=6,k=2,ans+=6;dfs(2,6,2)->ans-=42,lcm=42,k=3;接着深搜
这是容斥原理的一个最简单的应用,类比这道题,Step3到4其实将每个数a的不重复约数记录了下来,有公共约数的四个数的方案要从ans中减去,多减的要加上
奇加偶减
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#include<ctype.h>
#include<algorithm>
#include<string>
#define PI acos(-1.0)
#define maxn 15
#define INF 1<<25
typedef long long ll;
using namespace std;
ll n,m,ans=0,num[260],tot;
ll gcd(ll a,ll b)
{
return b==0?a:gcd(b,a%b);
}
void dfs(ll pos,ll pre_lcm,ll k)
{
for(ll i=pos;i<=tot;i++)
{
int lcm=pre_lcm/gcd(num[i],pre_lcm)*num[i];//求出他与pre_lcm的最小公倍数(利用最大公约数求)
if(k&1)ans+=(n-1)/lcm;
//若k是奇数,则加;偶数则减,称为奇加偶减。
else ans-=(n-1)/lcm;
dfs(i+1,lcm,k+1);//深搜下一个数,lcm更新,k加一,以上面的一组数字为例。
}
}
int main()
{
ll x,i,j;
while(scanf("%lld %lld",&n,&m)!=EOF)
{
memset(num,0,sizeof(num));
ans=0;
tot=0;
for(i=1;i<=m;i++)
{
cin>>x;
if(x>0&&x<n)
{
num[++tot]=x;
//先筛选出在0与n之间的数,这样的数才符合有可能被比n小的数整除。
}
}
dfs(1,1,1);//深度优先搜索,从第一个数开始,pre_lcm=1,k=1;k代表这一个数与其他数重叠次数。
cout<<ans<<endl;
}
}