HDU 3923 polya+乘法逆元+扩展欧几里德

polya计数原理参看:http://blog.csdn.net/wsniyufang/article/details/6671128

乘法逆元:百度

#include<iostream>
#include <stdlib.h>
#include <algorithm>
#include <stdio.h>
#include<vector>
using namespace std;
int prime[8084];
int isprime[10001];
int num,n,p;
const int Mod=1000000007;
void getprime()  
{  
    num=0;  
    for(int i=2;i<=10000;i++)if(!isprime[i])  
    {  
        prime[num++]=i;  
        for(int j=1;j*i<=10000;j++)  
        {  
            isprime[i*j]=1;  
        }  
    }  
}  
long long euler(int x)
{
	long long res=x;
	for(int i=0;prime[i]*prime[i]<=x&&i<num;i++)
	{
		if(x%prime[i]==0)
		{
			res=res/prime[i]*(prime[i]-1);
			while(x%prime[i]==0)
			{
				x/=prime[i];
			}
		}
	}
	if(x>1) res=res/x*(x-1);
	return res;
}
long long fun(int a,int b)
{
    long long ret=1;
    long long aa=a;
    while(b>0)
    {
        if(b&1)ret=(ret*aa)%1000000007;
        aa=(aa)*(aa)%1000000007;
        b>>=1;
    }
    return ret%1000000007;
}
__int64 Extend_euclid(__int64 a,__int64 b,__int64 &x,__int64 &y)
{
    __int64 d=0,t=0;
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    else
    {
        d=Extend_euclid(b,a%b,x,y);
        t=x;
        x=y;
        y=t-a/b*y;
    }
    return d;
}
__int64 Bignum_Div(__int64 a,__int64 b,__int64 mod)
{
    __int64 x=0,y=0;
    Extend_euclid(b,mod,x,y);//扩展gcd求出(2*n)*x-mod*k=1的x
    __int64 ans= a*x%mod;//ans/(2*n)%p = ((ans*x)/(2*n*x))%p=ans*x%mod; (p=1000000007,显然gcd(2*n,p)=1)
    while(ans<0)
        ans+=mod;
    return ans;
}

int main()
{
	getprime();
	int c,Case;
	scanf("%d",&Case);
	for(int k=1;k<=Case;k++)
	{
		scanf("%d%d",&c,&n);
		long long ans = 0;
		for (int i = 1; i <= n; i++)if (n % i == 0) 
		{
		ans = (ans+fun(c, i)* euler(n / i))%1000000007;
		}
		if (n & 1) ans =(ans+ n*(fun(c, n / 2 + 1)))%1000000007;
		else ans = (ans+n/2*(fun(c, n / 2)+ fun(c, n / 2 + 1)))%1000000007;
		ans=Bignum_Div(ans,2*n,1000000007);//不能直接ans/(2*n),因为ans是mod%1000000007的结果
		printf("Case #%d: %lld\n",k,ans);
		
	}
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值