容斥原理+dfs剪枝 -ost數(WOJ 2592)
阿新 • • 發佈:2018-12-18
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
考場上推了半天,倒是想出了容斥……奇加偶減。很好做啊,然後很多很多的怎麼弄啊 後來看題解發現就是dfs看每個數選還是不選,如果這次選出來的數個數為奇,就,否則就減 最後再把(17沒有被算)就可以得到答案了 再順手剪剪枝,比如: 當前時就不用繼續了
還有些細節要注意一下: 比如這樣寫是錯誤的 具體原因就是因為我們剪了枝,會導致多算的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;
}