题目链接: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[N],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;
}