八 (容斥)
阿新 • • 發佈:2020-10-07
題目描述
八是個很有趣的數字啊。
八=發,八八=爸爸,88=拜拜。
當然最有趣的還是 \(8\) 用二進位制表示是 \(1000\)。
怎麼樣,有趣吧。當然題目和這些都沒有關係。
某個人很無聊,他想找出 \([a,b]\) 中能被 \(8\) 整除卻不能被其他一些數整除的數。
輸入格式
第一行一個數 \(n\) ,代表不能被整除的數的個數。
第二行 \(n\) 個數,中間用空格隔開。
第三行兩個數 \(a,b\) ,中間一個空格。
輸出格式
一個整數,為 \([a,b]\) 間能被 整除卻不能被那 \(n\) 個數整除的數的個數。
樣例
樣例輸入
3 7764 6082 462 2166 53442
樣例輸出
6378
資料範圍與提示
對於 \(30\%\) 的資料, \(1\leqslant n\leqslant 5,1\leqslant a\leqslant b\leqslant 10^5\) 。
對於 \(100\%\) 的資料,\(1\leqslant n\leqslant 15,1\leqslant a\leqslant b\leqslant 10^9\) 。個數全都小於等於 \(10^4\) 大於等於 \(1\) 。
分析
首先考慮沒有限制的情況,也就是求 \([a,b]\) 中能被 \(8\) 整除的數的個數,答案容易得到是 \(\frac{8}{r} - \frac{8}{l-1}\)
Code
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn = 20;
ll a[maxn];
inline ll gcd(ll a,ll b){
if(b == 0)return a;
return gcd(b,a%b);
}
inline ll lcm(ll a,ll b){
return a * b / gcd(a,b);
}
int main(){
ll ans = 0;
int n;
scanf("%d",&n);
for(int i = 1;i <= n;++i){
scanf("%lld",&a[i]);
}
ll l,r;
scanf("%lld%lld",&l,&r);
ans += r / 8 - (l - 1) / 8;
ll mx = (1 << n) - 1;
for(ll s = 1;s <= mx;++s){
ll LCM = 8;
int cnt = 0;
for(int i = 1;i <= n;++i){
if(s & (1 << (i - 1)))LCM = lcm(LCM,a[i]),cnt++;
}
if(cnt & 1)ans -= r/LCM - (l - 1) / LCM;
else ans += r / LCM - (l - 1) / LCM;
}
printf("%lld\n",ans);
return 0;
}
\(Never\ Give\ Up\)