(三道题目的完整代码在文章最后)
这几道题都是有关互素和容斥原理的问题, 要求1~n 中与 m互质的自然数的个数的基本思路是:先找到m的所有质因数然后用容斥原理找出在1~n的范围内与m互质的数的个数。
以HDU4135(Coprime)为例。点击看原题
该题让我们找出在[a,b]内能被m整除的数目。求出1~m和1~n-1 的,相减即可。
首先是找出m的所有质因数:
vector<int > fac;
ll getPrimeFactor(ll n)
{
for(int i = 2 ; i*i <= n; i++)
{
if(n%i == 0)
{
fac.push_back(i);
while(n%i == 0) n/= i;
}
}
if(n!=1)
fac.push_back(n);
return fac.size();
}
容斥原理可以用DFS或者枚举子集的方法来写,下面是DFS的写法,每一次枚举当前的这个质因数要或者不要,最后如果看要了奇数个还是偶数个质因数,来判断符号是加还是减(若不太理解可以百度一下容斥原理),此处是用n来除以 所有取用的质因数的乘积 得到n中能被这些质因数都整除的自然数的个数,而在其他题目中会有变化,在后面会说到。
void dfs(int dep, int flag, ll number)
{
if(dep == num)
{
if(flag)
{
ansA -= a/number;
ansB -= b/number;
}
else
{
ansA += a/number;
ansB += b/number;
}
return;
}
dfs(dep+1,flag,number);
dfs(dep+1,!flag , number*fac[dep]);
}
POJ 2407 (Relatives)
点击查看原题
此题比上一题更为简单,直接求1~n的,我就把上一题的代码改了改。
HDU1796(How many integers can you find)
点击查看原题
这题给我们一个数n和一个集合,问1~n中能被该集合中至少任意一个数整除的数有多少。
之前两题我们也是求出一个集合(所有质因数),然后算1~n中能被该集合中的至少任意一个数整除的数有多少,所以此题方法也是容斥原理。但是,第一题中我有提到过此处有变化的地方,第一题中如果取用一个数就直接把它乘到之前所有取用的数的积上即可,而此处要取之前所有数的结果与当前取用的数的lcm,最小公倍数。因为之前的数都是质数,而此处不保证都是质数。可在代码中注意一下此处不同。
三道题的完整代码:
HDU4135(Coprime)
//Chirfen 2016.8.15
//Accepted 1592 KB 15 ms
//HDU 4135
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <map>
#include <queue>
#include <vector>
#include <utility>
#define SIZE 1000010
#define ll long long
using namespace std;
ll num ,ansA, ansB, a,b,n;
vector<int > fac;
ll getPrimeFactor(ll n)
{
for(int i = 2 ; i*i <= n; i++)
{
if(n%i == 0)
{
fac.push_back(i);
while(n%i == 0) n/= i;
}
}
if(n!=1)
fac.push_back(n);
return fac.size();
}
void dfs(int dep, int flag, ll number)
{
if(dep == num)
{
if(flag)
{
ansA -= a/number;
ansB -= b/number;
}
else
{
ansA += a/number;
ansB += b/number;
}
return;
}
dfs(dep+1,flag,number);
dfs(dep+1,!flag , number*fac[dep]);
}
int main()
{
int T ; cin >> T;
int _case = 1;
while(T--)
{
fac.clear();
scanf("%I64d %I64d %I64d",&a,&b,&n);
a--;
num = getPrimeFactor(n);
ansA = 0 ; ansB = 0;
dfs(0,0,1);
printf("Case #%d: %I64d\n",_case++, ansB - ansA);
}
//cout << "Hello world!" << endl;
return 0;
}
POJ 2407 (Relatives)
点击查看原题
//Chirfen 2016.8.15
//Accepted 692 KB 16 ms
//POJ 2407
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <map>
#include <queue>
#include <vector>
#include <utility>
#define SIZE 1000010
#define ll long long
using namespace std;
ll num , ans, n;
vector<int > fac;
ll getPrimeFactor(ll n)
{
for(int i = 2 ; i*i <= n; i++)
{
if(n%i == 0)
{
fac.push_back(i);
while(n%i == 0) n/= i;
}
}
if(n!=1)
fac.push_back(n);
return fac.size();
}
void dfs(int dep, int flag, ll number)
{
if(dep == num)
{
if(flag)
{
ans -= n/number;
}
else
{
ans += n/number;
}
return;
}
dfs(dep+1,flag,number);
dfs(dep+1,!flag , number*fac[dep]);
}
int main()
{
while(scanf("%I64d",&n) && n)
{
fac.clear();
num = getPrimeFactor(n);
ans = 0;
dfs(0,0,1);
printf("%I64d\n", ans);
}
//cout << "Hello world!" << endl;
return 0;
}
//Chirfen 2016.8.15
//Accepted 1576 KB 93 ms
//
#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <string>
#include <map>
#include <queue>
#include <vector>
#include <utility>
#define SIZE 1000010
#define ll long long
using namespace std;
ll num , ans, n , m;
vector<int > fac;
int gcd(int n, int m)
{
if(m==0)
return n;
return gcd(m,n%m);
}
int lcm(int n,int m)
{
return n/gcd(n,m)*m;
}
void dfs(int dep, int flag, ll number)
{
if(dep == num)
{
if(flag)
{
ans -= n/number;
}
else
{
ans += n/number;
}
return;
}
dfs(dep+1,flag,number);
dfs(dep+1,!flag , lcm(number,fac[dep]));
}
int main()
{
while(~scanf("%I64d %I64d",&n, &m))
{
n--;
fac.clear();
int temp;
int flag = 0;
for(int i = 0 ; i <m ;i++)
{
scanf("%d", &temp);
if(temp == 1) flag = 1;
if(temp != 0) fac.push_back(temp);
}
if(flag)
{
printf("%d\n",n);
continue;
}
num = fac.size();
ans = 0;
dfs(0,0,1);
printf("%d\n", n-ans);
}
//cout << "Hello world!" << endl;
return 0;
}
HDU1796(How many integers can you find)
点击查看原题