标签:存在 ret namespace long hdu 指定 符号 visible str
概念:简单而言就是求n个集合的并集的方法,求法是将每一项的概率相加再减去重复的部分,在这减去重复的过程中为了防止出现重复减的问题,要用到容斥原理
思路:假设范围为(a,b),给定数字为n,首先记下数字范围内数字个数(b-a+1)减去不n互质的数的个数结果就是答案 ,首先可以将给定的数分解质因数,然后对于构造的每一个数字(t),(b)范围内不与其互质的数有(b/t)个,利用容斥原理计算出b范围内不与n互质的数的个数最后减去这个个数,由于(1,a-1)是不在这个范围内的,因此要加上(1,a-1)范围内不与n互质的数的和。
解题代码:
#include <iostream>
using namespace std;
typedef long long ll;
const int maxn = 16384;
ll ele[maxn],tele[maxn],a,b,n,counter;
ll dec(ll x){//将n可以分解的质因数存在ele数组中
counter = 0;
for(ll i = 2;i*i <=x;i++){
if(x%i==0){
ele[counter++] = i;
while(x%i==0){
x/=i;
}
}
}
if(x>1)ele[counter++] = x;
return 0;
}
ll solve(ll x){ //容斥原理求解不满足解的个数
ll t = 0,tt,res = 0;
tele[t++] = -1;
for(int i = 0;i<counter;i++){
tt = t;
for(int j = 0;j<tt;j++){
tele[t++] = tele[j]*ele[i]*-1;
/*
计算每一个可以构造的因子的状态,以4为例就是计算
A+B+C+D-AB-AC-AD-BC-BC-CD+ABC+ABD+ACD+BCD-ABCD
在具体计算过程中,其产生的顺序是:
A+B-AB+C-AC-BC+ABC+D-AD-BD+ABD-BC+ACD+BCD-ABCD
产生后一项的符号与枚举过程中的每一项的相反,而每一次枚举都比上一次枚举多一项
在这个步骤时间复杂度是(1+n)*n/2 即O(n^2)
*/
}
}
for(int i = 1;i<t;i++){
res += x/tele[i];
/*
这里是在计算具体的每一项应当在结果中占的部分
*/
}
return res;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
int cnt = 1;
ll a,b,n;
while(t--){
cin >> a >> b >> n;
dec(n);//将n分解因数
//计算(a,b)范围内的个数,所以要计算b范围内的个数最后减去a范围内的个数得到答案
printf("Case #%d: %lld\n",cnt++,b-a+1-solve(b)+solve(a-1));
}
}
类似题目:【HDU】2841 Visible Trees,题目本质一样,求解范围内互质数的个数
例如: 长度为n的由数字0,1,2组成的序列,要求每个数字至少出现1次,这样的序列有多少种?
与求解互质数一样,转向其相反问题也就是不出现这些数字的序列 不出现其中某些数字的序列。之后即可利用容斥原理进行计算记A,B,C分别为不出现0,1,2的序列数,所以结果可以表示为A+B+C-AB-AC-BC+ABC.可以发现ABC的值都为2^n,而任意两个组合的值为1,故得到问题的解3^n - 3*2^n + 3*1 - 0;
标签:存在 ret namespace long hdu 指定 符号 visible str
原文地址:https://www.cnblogs.com/simulatedsakura/p/14171243.html