题解:P2155 [SDOI2008] 沙拉公主的困惑
题目大意
题意为求
思路
我们可以发现一个神奇的性质,由于
推论
证明:
先简化,我们知道
假设
此时
再推广,那么
由于
由于
所以对于每个
又由于共有
你可能会说除了
若一个数
根据欧几里得算法,可得
这时
这就说明一个与
证毕。
回到题目,此时答案即为
那么怎么得到
注意到
其中所有的
当
当
于是可以递推得到
细节
预处理后,除法用逆元处理即可,提交以后,恭喜你,炸了。
因为题目中并没有说明
所以,在预处理时,我们要将所有数写成
当两数相乘时将
最后,如果答案的
反之,如果答案的
代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
int qpow(int a, int b, int mod){ // 快速幂
int ans = 1, t = a;
for(; b > 0; b >>= 1){
if(b & 1) ans = ((ll)ans * t) % mod;
t = ((ll)t * t) % mod;
}
return ans;
}
const int N = 10000050;
int t, r, n, m, u, k;
int phia[N], phib[N]; // phia(i)的a和b
int tmsa[N], tmsb[N]; // i!的a和b
bool vis[N];
int main(){
cin >> t >> r;
vis[1] = 1;
// 埃氏筛筛质数
for(int i = 1; i < N; i ++)
if(!vis[i])
for(int j = i; (ll)j * i < N; j ++)
vis[i * j] = 1;
// 预处理
phia[0] = 1; phib[0] = 0; tmsa[0] = 1; tmsb[0] = 0;
for(int i = 1; i < N; i ++){
// 处理阶乘
u = i, k = 0;
while(u % r == 0) u /= r, k ++; // 将i中所有的r除出来
tmsa[i] = ((ll)tmsa[i - 1] * u) % r; /*将a相乘*/ tmsb[i] = tmsb[i - 1] + k /*将b相加*/;
// 处理phi前缀积
u = (vis[i] ? i : i - 1), k = 0;
while(u % r == 0) u /= r, k ++; // 将i中所有的r除出来
phia[i] = ((ll)phia[i - 1] * u) % r; /*将a相乘*/ phib[i] = phib[i - 1] + k /*将b相加*/;
}
while(t --){
scanf("%d%d", &n, &m);
int ans = (ll)tmsa[n] * phia[m] % r * qpow(tmsa[m], r - 2, r) % r; // 求出答案的a
if(tmsb[n] + phib[m] - tmsb[m] == 0) printf("%d\n", ans); // 若答案的b为零,输出ans的a
else printf("0\n"); // 否则答案为r的倍数,输出0
}
return 0;
}