cost数
描述
“给你一个有n个正整数的数列{an}。一个正整数x若满足在数列{an}中存在一个正整数ai,使x≡17(mod ai),那么x就是一个‘cost数’。请问1到m的正整数中,有多少个‘cost数’?”
输入
第一行两个正整数n和m,意义见问题描述。
第二行n个正整数,分别为数列{an}中的n个数。
输出
输出一个整数,表示1到m中“cost数”的个数。
样例输入
3 100
18 22 23
样例输出
11
【数据范围】
对于20%的数据,有n≤20,m≤100,000;
另有40%的数据,n≤3,m<2^31;
对于100%的数据,有n≤30,m<231,17<ai<231。
(注:“≡”为同余符号,a≡b (mod k) 即a mod k = b mod k)
Analysis
考场上推了半天,倒是想出了容斥……奇加偶减。
n
<
=
3
n<=3
n<=3很好做啊,然后很多很多的怎么弄啊
后来看题解发现就是dfs看每个数选还是不选,如果这次选出来的数个数为奇,就
a
n
s
+
=
(
m
−
17
)
/
l
c
m
ans+=(m-17)/lcm
ans+=(m−17)/lcm,否则就减
最后再把
a
n
s
+
1
ans+1
ans+1(17没有被算)就可以得到答案了
再顺手剪剪枝,比如:
当前
l
c
m
>
m
lcm>m
lcm>m时就不用继续了
还有些细节要注意一下:
比如这样写
a
n
s
+
=
m
/
l
c
m
,
a
n
s
−
=
(
n
−
1
)
ans+=m/lcm,ans-=(n-1)
ans+=m/lcm,ans−=(n−1)是错误的
具体原因就是因为我们剪了枝,会导致多算的17没有被减或者减多了
Code
#include<bits/stdc++.h>
#define in read()
#define ll long long
using namespace std;
inline int read(){
char ch;int f=1,res=0;
while((ch=getchar())<'0'||ch>'9') if(ch=='-') f=-1;
while(ch>='0'&&ch<='9'){
res=(res<<3)+(res<<1)+ch-'0';
ch=getchar();
}
return f==1?res:-res;
}
int n,m,a[40];
ll ans=0;
ll gcd(ll x,ll y){
ll z=x%y;
while(z){x=y;y=z;z=x%y;}
return y;
}
ll LCM(ll x,ll y){return x/gcd(x,y)*y;}
void dfs(int pos,ll lcm,int cnt){
if(pos==0){
if(lcm==1) return;//什么都不选的时候就没有意义啦
if(cnt&1) ans+=(m-17)/lcm;
else ans-=(m-17)/lcm;
return;
}
if(lcm>m) return;
ll tmp=LCM(lcm,a[pos]);
if(tmp<=m) dfs(pos-1,tmp,cnt+1);
dfs(pos-1,lcm,cnt);
}
int main(){
n=in;m=in;
int i,j,k;
for(i=1;i<=n;++i) a[i]=in;
sort(a+1,a+n+1);
dfs(n,1,0);
cout<<ans+1;
return 0;
}