洛谷2480 [SDOI2010]古代猪文

79 篇文章 0 订阅
76 篇文章 0 订阅

标签:数论,Lucas定理,CRT,快速幂

题目

题目传送门

计算 G ∑ i ∣ n C ( n , i ) % P G^{\sum_{i|n} C(n,i)} \% P GinC(n,i)%P

100 % 100\% 100%的数据中, 1 ≤ G ≤ 1000000000 , 1 ≤ N ≤ 1000000000 1\leq G\leq 1000000000,1\leq N \leq 1000000000 1G10000000001N1000000000

分析

根据费马小定理,指数可以变成

∑ i ∣ n C ( n , i ) % ( P − 1 ) \sum_{i|n} C(n,i)\%(P-1) inC(n,i)%(P1)

然后可以使用Lucas定理快速求组合数,之后用快速幂求出答案

999911659的约数有2,3,4679,35617,分别对这四个约数求组合数,之后使用CRT合并

code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cmath>
#include<cstring>
#include<algorithm>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define dep(i,a,b) for(int i=a;i>=b;i--)
#define ll long long
#define mem(x,num) memset(x,num,sizeof x)
#define reg(x) for(int i=last[x];i;i=e[i].next)
using namespace std;
inline ll read(){
	ll f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
//******head by yjjr******
#define mod 999911659
const int maxn=4e5+6;
int g,n,m[4],fac[4][maxn];
int t[4]={2,3,4679,35617};
inline ll qpow(ll a,ll b,int p){
	ll re=1;
	while(b){
		if(b&1)re=(ll)(re*a)%p;
		b>>=1,a=(ll)(a*a)%p;
	}
	return re;
}
inline ll C(int n,int m,int x){
	if(n<m)return 0;
	return (ll)(1ll*fac[x][n]*qpow(fac[x][n-m]*fac[x][m],t[x]-2,t[x])%t[x]);
}
inline ll Lucas(int n,int m,int x){
	if(m==0)return 1;
	return (ll)(1ll*C(n%t[x],m%t[x],x)*Lucas(n/t[x],m/t[x],x)%t[x]);
}
void exgcd(int a,int b,int &x,int &y){
	if(b==0){x=1,y=0;return;}
	exgcd(b,a%b,x,y);
	int t=x;x=y;y=t-a/b*y;
}
inline ll solve(){
	int a1,b1,a2,b2,a,b,c,x,y;
	a1=t[0],b1=m[0];
	rep(i,1,3){
		a2=t[i],b2=m[i];
		a=a1,b=a2,c=b2-b1;
		exgcd(a,b,x,y);
		x=((x*c)%b+b)%b;
		b1=b1+a1*x;
		a1=a1*b;
	}
	return b1;
}
int main(){
	rep(i,0,3){
		fac[i][0]=1;
		rep(j,1,t[i])fac[i][j]=(fac[i][j-1]*j)%t[i];
	}
	n=read(),g=read();
	if(g==mod){puts("0");return 0;}
	g%=mod;
	for(int i=1;i*i<=n;i++) 
		if(n%i==0){
			int tmp=n/i;
			rep(j,0,3){
				if(tmp!=i)m[j]=(m[j]+Lucas(n,i,j))%t[j];
				m[j]=(m[j]+Lucas(n,tmp,j))%t[j];
			}
		}
	cout<<qpow(g,solve(),mod)<<endl;
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值