poj 1091 跳蚤

来源:互联网 发布:淘宝平铺图 编辑:程序博客网 时间:2024/06/10 23:56

终于知道容斥定理是个啥玩意了,真神奇。

题意略,其实幻化为表达式就是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;}


原创粉丝点击