这题是个毒瘤题。你基本上要把你知道的数论算法都写上才能过。
题意简述
求,其中。(看不清的话右键公式,点击)
思路
用扩展:定理暴力求上面的,枚举因数是根号的,是带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;
}