[NOIP模拟][容斥原理][快速幂]Heal

样例输入1:

2 3

样例输出1:

8

样例输入2:

8 8

样例输出2:

16711680

题目分析:
考场总结:对于这道题无话可说,有一种难度叫读不懂题。考试时前面题花的时间比较多,然后面对这道长达2页的题(以某种鬼畜的言情风格写了一大堆废话包裹题面),我愣是没有读懂,实际上这道题的题目要求转化一下,就比较简单(以前还做过一道这样的题,那道题的题面没有这么复杂),比前面的两道都还简单·····所以啊,一道题不够难,可以通过题面来增加其难度。
分析:所以这道题最后的意思就是求给定m,选取n个小于等于m的数(可以相同),使得这个n+1数整体互质及gcd为1,有多少种组合。那么我们可以用整体减不互质的组合。整体是 mn (因为可以取相同的数)。而m是已知的,所以求出m的质因子,如果整体不互质,那么gcd只能是m的约数,所以容斥:减去gcd为一个质因子的个数的n次方,加上gcd为两个质因子的乘积的个数的n次方,减去3个·········
附代码:

#include<iostream>
#include<cstring>
#include<string>
#include<cstdlib>
#include<cstdio>
#include<ctime>
#include<cmath>
#include<iomanip>
#include<cctype>
#include<algorithm>
using namespace std;

const int mod=1e9+7;
const int N=1e6;
int tot,num;
long long n,m,q[N],zhi[N],ans,p;

long long ksm(long long x,long long y)
{
    long long ret=1;
    x%=mod;
    for(;y;y/=2,x=(x*x)%mod)
        if(y&1) ret=(ret*x)%mod;
    return ret;
}

void dfs(int cnt,int po,long long sum)//求一定个数质因子的乘积
{
    if(cnt==0)
    {
        q[++tot]=sum;
        return;
    }
    for(int i=po;i<=num;i++)
        dfs(cnt-1,i+1,sum*zhi[i]);
}

void find(int x,int ci)//容斥
{
    if(x==0) return;
    tot=0;
    dfs(num-x+1,1,1);
    for(int i=1;i<=tot-cnt+1;i++)
        ans=(ans+mod+ksm(m/q[i],n)*ci)%mod;
    find(x-1,ci*(-1));
}

int main()
{
    //freopen("heal.in","r",stdin);
    //freopen("heal.out","w",stdout);

    scanf("%I64d%I64d",&n,&m);
    p=m;
    for(long long i=2;i*i<=p;i++)//求m的质因子
    {
        if(p%i==0)
        {
            zhi[++num]=i;
            while(p%i==0)
            {
                p/=i;
            }
        }
    }   
    if(p>1) zhi[++num]=p;
    ans=ksm(m,n);
    find(num,-1);
    printf("%I64d",ans);

    return 0;
}
发布了99 篇原创文章 · 获赞 8 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/qianguch/article/details/78373974
今日推荐