关于数的容斥定理的代码实现
2017-11-30 21:16
141 查看
前述:其实容斥定理的用法并非自己感悟出来的,还是从大量博客里学习的,感觉这种深邃的思想我学不来,看题目的时候都想不到为什么要那样用,但是容斥定理本身是很简单的,公式我就不再展示了。但是还好因为集合的交集的求法比较困难,使得这方面能用固定代码解决的问题的种类大大减少。其中比较广泛的一个应用就是求1-m里面和n互质的数的个数。思路是用m-所有和n非互质的数的和,那么,和n非互质又有一个说法就是和n有大于1的公共素因子,而属于有某个因子a的数的个数的集合个数就是m/a。这样,问题就转化成了这样几个步骤:1.先求n的所有素因子。2.根据容斥定理求和n非互质的数的个数。3.ans=m-和n非互质的数的个数。那么这里我为啥说是代码实现而不说是模板呢,在dalao的博客里面我发现的写法要么是难懂的位运算,要么不用递归难想,而我选择了最直接也可能是最耗时间的解决方法,就是dfs递归,一开始只是出于试探的心理,后来交了几个题目之后发现并未出现超时的现象,于是就当作一个模板来用了,也做出来不少容斥定理的题目。
AC代码:(参见题目:HDU-4135 J - Co-prime )
题目大意:让求一个区间里面和n互质的数的个数。
解题思路:假设为[l,r],那么有可以用1-r满足条件的数的个数1-l-1中满足条件的数的个数。
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
long long fac[1100];
long long box[1100];
long long n,m,t;
long long fun;
long long gcd(long long a,long long b){
return b==0?a:gcd(b,a%b);
}
void getfac(){
long long i,j;
long long xx=n;
m=0;
for (i=2;i<=sqrt(n);i++){
if (xx%i==0){
fac[++m]=i;
while (xx%i==0){
xx/=i;
}
}
}
if (xx>1)fac[++m]=xx;
}
void sfind(long long x,long long y,long long z,long long val){
long long i,j;
for (i=x;i<=m;i++){
box[y]=fac[i];
if (y==z){
long long temp=1;
for (j=1;j<=z;j++){
temp=temp/gcd(temp,box[j])*box[j];
}
fun+=val/temp;
}
else sfind(i+1,y+1,z,val);
}
}
long long solve(long long x){
long long i,j;
long long temp=1;
long long ans=0;
for (i=1;i<=m;i++){
fun=0;
sfind(1,1,i,x);
ans+=fun*temp;
temp=-temp;
}
return x-ans;
}
int main(){
long long i,j,k,l,r,total,cas=0;
scanf("%lld",&t);
while (t--){
scanf("%lld%lld%lld",&l,&r,&n);
getfac();
long long ans=solve(r)-solve(l-1);
printf("Case #%lld: %lld\n",++cas,ans);
}
}
这个题目其实不是我创造出来这个写法的初始版本,这里改造成了一个函数,可以更为广泛的应用。
AC代码:(参见题目:HDU-4135 J - Co-prime )
题目大意:让求一个区间里面和n互质的数的个数。
解题思路:假设为[l,r],那么有可以用1-r满足条件的数的个数1-l-1中满足条件的数的个数。
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
long long fac[1100];
long long box[1100];
long long n,m,t;
long long fun;
long long gcd(long long a,long long b){
return b==0?a:gcd(b,a%b);
}
void getfac(){
long long i,j;
long long xx=n;
m=0;
for (i=2;i<=sqrt(n);i++){
if (xx%i==0){
fac[++m]=i;
while (xx%i==0){
xx/=i;
}
}
}
if (xx>1)fac[++m]=xx;
}
void sfind(long long x,long long y,long long z,long long val){
long long i,j;
for (i=x;i<=m;i++){
box[y]=fac[i];
if (y==z){
long long temp=1;
for (j=1;j<=z;j++){
temp=temp/gcd(temp,box[j])*box[j];
}
fun+=val/temp;
}
else sfind(i+1,y+1,z,val);
}
}
long long solve(long long x){
long long i,j;
long long temp=1;
long long ans=0;
for (i=1;i<=m;i++){
fun=0;
sfind(1,1,i,x);
ans+=fun*temp;
temp=-temp;
}
return x-ans;
}
int main(){
long long i,j,k,l,r,total,cas=0;
scanf("%lld",&t);
while (t--){
scanf("%lld%lld%lld",&l,&r,&n);
getfac();
long long ans=solve(r)-solve(l-1);
printf("Case #%lld: %lld\n",++cas,ans);
}
}
这个题目其实不是我创造出来这个写法的初始版本,这里改造成了一个函数,可以更为广泛的应用。
相关文章推荐
- 关于对H264码流的PS的封装的相关代码实现
- 关于无限分级(ASP+数据库+JS)的实现代码
- 关于dtree树代码实现带checkox修改的最新思路
- 由于自己的需要搜集的一些关于 “ javascript实现图片的不间断连续滚动” 的代码
- 关于iCloud的注册,到代码的实现
- 关于对H264码流的PS的封装的相关代码实现
- 关于用Java实现发送邮件(部分代码参考网络来源)
- 关于用Java实现发送短信(部分代码来源于网络)
- 以下是关于对称加密算法的C#实现代码,大家可以根据需要更改不同的算法,文中以Rijndael算法为例
- 关于 数据源 导出excel (这是) 通过 画一个html 实现的、最简单、好理解、的代码、
- 记录一次有关于实现新闻下一篇功能的代码优化
- cocos 3.X 关于代码实现一段动画的播放 20180312 day4
- 关于冒泡排序的Java代码实现
- 关于代码实现一个数求平方根
- 由于自己的需要搜集的一些关于 “ javascript实现图片的不间断连续滚动” 的代码
- 关于ASP.NET MVC框架的代码提示汉化实现方法
- 关于对H264码流的TS的封装的相关代码实现
- 关于storybord加视图控制器的代码实现方式
- 关于JAVA中事件分发和监听机制实现的代码实例-绝对原创实用
- 关于抽象工厂实现数据库查询的设计(JAVA代码实现)