这题是个毒瘤题。你基本上要把你知道的数论算法都写上才能过。
题意简述
求,其中。(看不清的话右键公式,点击)
思路
用扩展:定理暴力求上面的,枚举因数是根号的,是带log的,所以能过。然后无哦们用欧拉降幂对质数取膜。取膜完发现这还不是个质数,所以要用中国剩余定理合并答案。
具体思路
step.1 假设我们能算上面那个
我们发现那个膜数是个质数。那么它的值就是。
然后我们把它分解,它。我们只要以这四个数作为膜数,分别求出答案,然后用中国剩余定理合并一下即珂。就相当于求出四个答案,然后解方程:
这个方程很容易解。珂是如何求上面那个呢?
step.2 上面那个
枚举的话是,但是我们还要快速的求组合数。考虑扩展卢卡斯定理:
。然后对于后面那个,我们只要预处理出$1,p$之间阶乘和阶乘的逆元即珂。然后这个预处理不是每次都要预处理的,每次算之前预处理一下即珂。复杂度之和是,珂以忽略不计。然后这样递归求的话,大概总的复杂度是。是能过的。
好了,就到这里了,很短。但是要写很多东西。
step.3 快速幂 略
实现细节
- 特判的情况,输出(要不然你就会到自闭)
代码:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
using namespace std;
namespace Flandre_Scarlet
{
	
	
	
	
	
	
	
	
	
	
	int n,g;
	void R1(int &x)
	{
	    x=0;char c=getchar();int f=1;
	    while(c<'0' or c>'9') f=(c=='-')?-1:1,c=getchar();
	    while(c>='0' and c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
	    x=(f==1)?x:-x;
	}
	void Input()
	{
		R1(n),R1(g);
	}
	int fac[P],ifac[P];//预处理阶乘和阶乘的逆元
	int qpow(int a,int b,int m)//快速幂
	{
		int r=1;
		while(b)
		{
			if (b&1) r=r*a%m;
			a=a*a%m,b>>=1;
		}
		return r;
	}
	int C1(int n,int k,int p)//求一个组合数
	{
		if (n<k) return 0;
		if (k==0 or k==n or n==0) return 1; 
		return fac[n]*ifac[k]%p*ifac[n-k]%p;
                //仅限n,k<=p的情况,要不然有一个是0就除爆了
	}
	int C(int n,int k,int p)
	{
		if (n<k) return 0;
		if (k==0 or k==n or n==0) return 1; 
		return C(n/p,k/p,p)*C1(n%p,k%p,p)%p;//Lucas定理
	}
	int calc(int n,int p)
	{
		fac[0]=1;
		F(i,1,p) fac[i]=fac[i-1]*i%p;
		ifac[p-1]=qpow(fac[p-1],p-2,p);
		D(i,p-2,1) ifac[i]=ifac[i+1]*(i+1)%p;//预处理
		int ans=0;
		for(int i=1;i*i<=n;++i)//枚举因数
		{
			if (n%i==0)
			{
				int a=i;
				ans+=C(n,a,p);//暴力计算
				ans%=p;
				if (i*i!=n)//别忘了判这个
				{
					int b=n/i;
					ans+=C(n,b,p);//暴力计算
					ans%=p;
				}
			}
		}
		return ans;
	}
	int a[5],b[5];
	int CRT()
	{
		int ans=0;
		F(i,1,4)
		{
			ans=(ans+a[i]*(mod/b[i])%mod*qpow(mod/b[i],b[i]-2,b[i]))%mod;
		}
		return ans;//扩展中国剩余定理
	}
	void Soviet()
	{
		if (g%(mod+1)==0)//会导致你WA掉的特判
		{
			puts("0");
			return;
		}
		b[1]=2,b[2]=3,b[3]=4679,b[4]=35617;//四个膜数
		F(i,1,4)
		{
			a[i]=calc(n,b[i]);//算出四个答案
		}
		printf("%lld\n",qpow(g,CRT(),mod+1)%(mod+1));
                //别忘了最后输出g^CRT,而且膜数是mod+1,我令mod=
	}
	void IsMyWife()
	{
		Input();
		Soviet();
	}
	
}
int main()
{
	Flandre_Scarlet::IsMyWife();
	getchar();getchar();
	return 0;
}