终于知道容斥定理是个啥玩意了,真神奇。
题意略,其实幻化为表达式就是a1*num1+a2*num2+a3*num3+......an*numn = 1;本人没学过数论,但是一眼就看出这个表达式的意思就是说这n个数的gcd为1,结果baidu了一下,竟然真中枪了,原话是这样的(n个数的最大公约数规定为这n个数线性和的最小自然数,所以此题就是要求最大公约数为1的数列的个数);其实这题数据很水,明显会用到高精度的,但是用__int64就能低空水过掉(水是一种风格),算gcd为1的数列种数肯定不好算,然后换个方向来进行计思考,可以先算出总数目m^n然后减去gcd不为1的,gcd不为1的情况有很多重复的,这时又得用到组合数学中的容斥定理(很经典的,用处也很多,不妨学一下。),这组合数学不懂真心完全理解不了,相信看完容斥定理的人看我代码也就懂了。
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 101;
int cou;
typedef struct {
int i,flag;
}Node;
Node arr[N];
bool cmp(Node a,Node b)
{
return a.i<b.i;
}
__int64 mypow(__int64 a,__int64 b)
{
__int64 sum = 1;
while(a--)
{
sum *= b;
}
return sum;
}
void getdiv(__int64 m)
{
int n = 1;
int i;
for(i=2;i*i<m;++i)
if(m%i==0)
{
arr[n++].i = i;
arr[n++].i = m/i;
}
if(i*i==m)
{
arr[n++].i = i;
}
arr[n++].i = m;
sort(arr+1,arr+n,cmp);
cou = n;
for(int i=1;i<cou;++i)
{
bool flag = true;
int k = 0;
for(int j=1;j<i;++j)
if(arr[j].flag==1&&arr[i].i%arr[j].i==0)
{
++k;
flag = false;
if(arr[i].i%(arr[j].i*arr[j].i)==0)
{
k = 0;
break;
}
}
if(!flag)
arr[i].flag = k;
else
arr[i].flag = 1;
}
}
int main(void)
{
int n,m;
while(scanf("%d %d",&n,&m)!=EOF)
{
__int64 ans = mypow(n,m);
getdiv(m);
for(int i=1;i<cou;++i)
{
if(arr[i].flag==0)
;
else if(arr[i].flag%2)
{
ans -= mypow(n,m/arr[i].i);
}
else
{
ans += mypow(n,m/arr[i].i);
}
}
cout<<ans<<endl;
}
return 0;
}
本文深入探讨了容斥定理在解决数论问题中的作用,通过实例展示了如何利用该原理求解特定类型的数学问题,并提供了高效算法实现的代码示例。文中还详细介绍了如何计算具有特定性质的数列数量,涉及高精度计算和组合数学的容斥定理。通过数据简化和容斥定理的应用,文章提供了一种快速解决问题的方法。
676

被折叠的 条评论
为什么被折叠?



