poj 1091 跳蚤 (数论,容斥原理)

题意:

一只小跳蚤想要迟到它左边的食物,但是跳蚤只能按照某张牌上的数字进行往左或者往右的跳跃。牌中数字有N+1个,并且最后一个一定是M,其他的不比M大。问在所有的组合M^N中有多少张牌是可以让跳蚤迟到食物的。注意,牌上的数字可以重复使用。

题解:

这种题目下手要寻找一个规律,规律就是突破口,我们要得到那些性质的数组成的牌能让跳蚤迟到食物。发现这些数如果公约数为1那么跳蚤就可以吃到食物,那么我们求逆问题,哪些数公约数大于1,既然M是固定的,那么要满足公约是大于1,其他的数必定要与M不互质!那么与M不互质的数可定是M质因子的倍数,那么对于某个质因数它能得到的方案树:(M/x)^N。但是会发现某写x^2等于某些y^3这里含着重复,于是根据容斥原理,dfs求解。

#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<string>
#include<vector>
#include<queue>
#include<map>
#include<set>
using namespace std;
#define B(x) (1<<(x))
void cmax(int& a,int b){ if(b>a)a=b; }
void cmin(int& a,int b){ if(b<a)a=b; }
typedef long long ll;
const int oo=0x3f3f3f3f;
const ll OO=1LL<<61;
const int MOD=1000007;
const int maxn=100005;
set<ll>g;
ll N,M;

ll quick_pow(ll a,ll k){
    ll ans=1;
    while(k){
        if(k&1) ans*=a;
        a*=a;
        k>>=1;
    }
    return ans;
}

ll dfs(set<ll>::iterator s,ll x){
    ll res=0,cnt,t;
    for(set<ll>::iterator it=s;it!=g.end();++it){
        t=x/(*it);
        cnt=quick_pow(t,N);
        it++;
        res+=cnt-dfs(it,t);
        it--;
    }
    return res;
}

void fac(ll n){
    g.clear();
    for(int i=2;i*i<=n;i++){
        while(n%i==0){
            g.insert(i);
            n/=i;
        }
    }
    if(n>1)
        g.insert(n);
}

int main(){
    //freopen("E:\\read.txt","r",stdin);
    int T;
    while(scanf("%I64d %I64d",&N,&M)!=EOF){
        fac(M);
        ll ans=quick_pow(M,N)-dfs(g.begin(),M);
        printf("%I64d\n",ans);
    }
    return 0;
}





你可能感兴趣的:(poj 1091 跳蚤 (数论,容斥原理))