原文链接 https://www.cnblogs.com/cly-none/p/SRM704Div1B.html

给出\(n\)和模数\(P\)。\(q\)次询问,每次给出一个\([0,P-1]\)范围内的整数\(v\),求有多少长度为\(n\)的序列\(\{x\}\)满足\(x_i\)都是\([0,P-1]\)范围内的整数且\(\prod x_i \equiv v \pmod P\),答案对\(10^9 + 7\)取模。

\(n \leq 50 , \ q \leq 10^3, \ P \leq 10^9\)

注意:\(P\)不是质数。

这题大概就是道结论题。

首先,我们容易得到\(O(n P^2)\)的dp。

考虑\(P\)为质数的情况。我们发现,对于所有\(a \neq 1\),\(\{a, 2a, \cdots, (P-1)a\}\)都是互不相等的,即它在模\(P\)意义下就是\(\{1, 2, \cdots , P-1\}\)。那么,在dp中\(1\)到\(P-1\)的所有数的转移都是相同的,那它们的答案也应当是相等的。

尝试把这个结论拓展到\(P\)为正整数的情况下。我们设模\(P\)意义下的每个数 $v = v' \times d $ ,其中 \(d=gcd(v,P)\) 。同样地,\(\{ v', 2v', \cdots , (P-1)v' \}\)互不相等,于是 \(v\) 乘以\(1\)到\(P-1\)的所有数就是\(\{d, 2d, \cdots , (P-1)d \}\)。于是,我们发现\(gcd(x,P)\)相同的\(x\)在dp中有相同的转移,那就可以把它们的状态合并在一起。这样这个dp就优化到了\(O(n \sigma (n)^2)\)的了,已经可以通过本题。

但我们还可以套路地对\(P\)做质因数分解,得到\(P = p_1^{a_1} p_2^{a_2} \cdots p_n^{a_n}\),然后以每个\(p_i^{a_i}\)为模数,分别求一次答案。考虑所有模\(P\)意义下的数和模\(p_i^{a_i}\)得到的序列是一一对应的,所以我们可知答案就是以每个\(p_i^{a_i}\)为模数的答案的积。那么,就能\(O(n \log^2 P + q \log P)\)地解决本题。(这里的\(\log P\)分析并不准确)

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef double db;
#define fir first
#define sec second class ModEquation {
public:
vector <int> count( int n, int K, vector <int> query ) ;
};
const int MAX = 100000, MP = 30, N = 60, MOD = (int)(1e9 + 7);
int isp[MAX + 10], pri[MAX], pcnt, fac[MP], fcnt, num[MP];
int power(int a,int b) {
int ret = 1;
while (b) {
if (b & 1) ret = 1ll * ret * a % MOD;
a = 1ll * a * a % MOD;
b >>= 1;
}
return ret;
}
void prework() {
for (int i = 2 ; i <= MAX ; ++ i) {
if (!isp[i]) pri[++pcnt] = i;
for (int j = 1 ; pri[j] * i <= MAX ; ++ j) {
isp[pri[j] * i] = 1;
if (i % pri[j] == 0) break;
}
}
}
int dp[MP][N][MP];
void init() {
pcnt = fcnt = 0;
memset(isp,0,sizeof isp);
memset(dp,0,sizeof dp);
}
vector <int> ModEquation::count(int n, int K, vector <int> query) {
init();
prework();
for (int i = 1 ; i <= pcnt ; ++ i) {
if (K % pri[i]) continue;
fac[++fcnt] = pri[i];
num[fcnt] = 0;
while (K % pri[i] == 0)
++ num[fcnt], K /= pri[i];
}
if (K != 1) {
++ fcnt;
fac[fcnt] = K;
num[fcnt] = 1;
}
for (int i = 1 ; i <= fcnt ; ++ i) {
dp[i][0][0] = 1;
for (int j = 0 ; j < n ; ++ j) {
for (int a = 0 ; a <= num[i] ; ++ a)
for (int b = num[i], t = 1 ; b >= 0 ; -- b, t *= fac[i]) {
(dp[i][j+1][min(num[i], a + b)] += 1ll * dp[i][j][a] * (t - t / fac[i]) % MOD) %= MOD;
}
}
for (int a = num[i], t = 1 ; a >= 0 ; -- a, t *= fac[i]) {
dp[i][n][a] = 1ll * dp[i][n][a] * power(t - t / fac[i], MOD - 2) % MOD;
}
}
vector<int> ans = vector<int>();
for (int id = 0 ; id < (int)query.size() ; ++ id) {
int v = query[id], ret = 1;
for (int i = 1 ; i <= fcnt ; ++ i) {
int tmp = v, rec = 0;
for (int j = 1 ; j <= num[i] ; ++ j)
if (tmp % fac[i] == 0) tmp /= fac[i], ++ rec;
ret = 1ll * ret * dp[i][n][rec] % MOD;
}
ans.push_back(ret);
}
return ans;
} #undef fir
#undef sec

小结:数论题有一些基本结论和套路还是非常重要的。

最新文章

  1. MySQL 性能调优之查询优化
  2. react实现的tab切换组件
  3. GitHub访问速度慢的解决方法
  4. BZOJ3636: 教义问答手册
  5. 软件需求分析之NABCD模型
  6. (转)onTouchEvent方法的使用
  7. Object-c学习之路七(oc字符串操作)
  8. sql2008r2局域网复制订阅实操
  9. JavaScript设计模式--门面模式
  10. Hibernate中配置文件的学习
  11. django 关于视频播放
  12. Asp.net Core认证和授权:Cookie认证
  13. GDB调试qemu源码纪录
  14. #C语言初学记录(位运算)
  15. 50个国内外最棒的C/C++源码站点分享
  16. 网站漏洞扫描工具Uniscan
  17. 33.使用默认的execAndWait拦截器
  18. springboot手动配置数据源:
  19. CS20Chapter3
  20. 「Leetcode」975. Odd Even Jump(Java)

热门文章

  1. dddquickly
  2. CatLog_小鱼要加油
  3. C# 图片识别
  4. 多线程深入:让你彻底理解Synchronized(转)
  5. Movavi Video Editor 15 Plus(视频编辑软件) 中文版
  6. vs2017无法安装
  7. 【actitivi】配置运行上遇到的问题
  8. PHP防CC攻击代码
  9. git提交到一半关闭时
  10. python安装画图模块pillow