您的位置:首页 > 其它

POJ1091 跳蚤 【容斥】

2017-08-28 16:40 387 查看
题目链接:http://poj.org/problem?id=1091

解题报告:

设数字分别为a1,a2,a3……m,那么若方程x1a1+x2a2+……xn+1m=1有解,则这张卡片可行。而此方程有解的充要条件为gcd(a1,a2,a3……m)=1,所以本题即为求gcd(a1,a2,a3……m)=1,1≤a1,a2,a3……an≤m的方案数。

那么可以反着求gcd(a1,a2,a3……m)≠1,1≤a1,a2,a3……m≤m的方案数。,再用总方案数nm减去即可。

又因为m是知道的,所以可以先将m分解质因数为p1,p2,p3……pcnt,那么a1,a2,a3……m有公因子px的方案数即为⌊mpx⌋n,但会算重,容斥一下即可,我的代码中是用二进制数表示选哪几个质因子的,也可以深搜。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
#define ll unsigned long long
using namespace std;

const int N=35;
int n,m,p
,cnt;
ll ans=1;

int getint()
{
int i=0 ,f=1;char c;
for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar());
if(c=='-')f=-1,c=getchar();
for(;c>='0'&&c<='9';c=getchar())i=(i<<3)+(i<<1)+c-'0';
return i*f;
}

int main()
{
//freopen("flea.in","r",stdin);
//freopen("flea.out","w",stdout);
ll tot,tmp;
int f,d;
n=getint(),m=getint();
tmp=m;
for(int i=2;i*i<=m;i++)
{
if(tmp%i==0)p[++cnt]=i;
while(tmp%i==0)tmp/=i;
}
if(tmp>1)p[++cnt]=tmp;
for(int i=1;i<=n;i++)ans*=m;
for(ll i=1;i<(1<<cnt);i++)
{
tmp=i,f=1,d=1,tot=1;
for(int j=1;j<=cnt;j++)
{
if(tmp&1)d*=p[j],f*=-1;
tmp>>=1;
}
for(int j=1;j<=n;j++)tot*=m/d;
ans+=tot*f;
}
cout<<ans;
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: