【做题】SRM704 Div1 Median - ModEquation——数论
原文链接 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
小结:数论题有一些基本结论和套路还是非常重要的。
【做题】SRM704 Div1 Median - ModEquation——数论的更多相关文章
- [日记&做题记录]-Noip2016提高组复赛 倒数十天
写这篇博客的时候有点激动 为了让自己不颓 还是写写日记 存存模板 Nov.8 2016 今天早上买了两个蛋挞 吃了一个 然后就做数论(前天晚上还是想放弃数论 但是昨天被数论虐了 woc noip模拟赛 ...
- noip做题记录+挑战一句话题解?
因为灵巧实在太弱辽不得不做点noip续下命QQAQQQ 2018 积木大赛/铺设道路 傻逼原题? 然后傻逼的我居然检查了半天是不是有陷阱最后花了差不多一个小时才做掉我做过的原题...真的傻逼了我:( ...
- NOIP2016考前做题(口胡)记录
NOIP以前可能会持续更新 写在前面 NOIP好像马上就要到了,感觉在校内训练里面经常被虐有一种要滚粗的感觉(雾.不管是普及组还是提高组,我都参加了好几年了,结果一个省一都没有,今年如果还没有的话感觉 ...
- UOJ 做题记录
UOJ 做题记录 其实我这么弱> >根本不会做题呢> > #21. [UR #1]缩进优化 其实想想还是一道非常丝播的题目呢> > 直接对于每个缩进长度统计一遍就好 ...
- C语言程序设计做题笔记之C语言基础知识(下)
C 语言是一种功能强大.简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定的任务.我们可以利用C语言创建程序(即一组指令),并让计算机依指令行 事.并且C是相当灵活的,用于执行计算机程序能完成的 ...
- C语言程序设计做题笔记之C语言基础知识(上)
C语言是一种功能强大.简洁的计算机语言,通过它可以编写程序,指挥计算机完成指定的任务.我们可以利用C语言创建程序(即一组指令),并让计算机依指令行事.并且C是相当灵活的,用于执行计算机程序能完成的几乎 ...
- 屏蔽Codeforces做题时的Problem tags提示
当在Codeforces上做题的时,有时会无意撇到右侧的Problem tags边栏,但是原本并不希望能够看到它. 能否把它屏蔽了呢?答案是显然的,我们只需要加一段很短的CSS即可. span.tag ...
- ACM 做题过程中的一些小技巧。
ACM做题过程中的一些小技巧. 1.一般用C语言节约空间,要用C++库函数或STL时才用C++; cout.cin和printf.scanf最好不要混用. 2.有时候int型不够用,可以用long l ...
- CodeM美团点评编程大赛复赛 做题感悟&题解
[T1] [简要题意] 长度为N的括号序列,随机确定括号的方向:对于一个已确定的序列,每次消除相邻的左右括号(右左不行),消除后可以进一步合并和消除直到不能消为止.求剩下的括号的期望.\(N \l ...
随机推荐
- LeetCode 606 Construct String from Binary Tree 解题报告
题目要求 You need to construct a string consists of parenthesis and integers from a binary tree with the ...
- POI导出excel列宽自适应
让单元格宽度随着列和单元格值的宽度自适应: //存储最大列宽 Map<Integer, Integer> maxWidth = new HashMap<>(); // 将列头设 ...
- C++ opencv调用resize修改插值方式遇到的坑
opencv提供的热死则函数原型如下:void resize(InputArray src, OutputArray dst, Size dsize, double fx=0, double fy=0 ...
- springboot+spring security +oauth2.0 demo搭建(password模式)(认证授权端与资源服务端分离的形式)
项目security_simple(认证授权项目) 1.新建springboot项目 这儿选择springboot版本我选择的是2.0.6 点击finish后完成项目的创建 2.引入maven依赖 ...
- JSTL将number类型转化为String类型
<c:set var="lm1"> <c:out value="${lm}" /> </c:set>
- Get Random number
, int pMaxVal = int.MaxValue) { int m = pMaxVal - pMinVal; int rnd = int.MinValue; decimal _base = ( ...
- visual studio 启动报 activityLog.xml文件 错误
1.在安装目录里面找到 devenv.exe 这个文件的所在位置C:\Program Files\Microsoft Visual Studio 10.0\Common7\IDE 2.点击左下角图标, ...
- java 对象的一点小问题
List<A> list = new ArrayList(); A a = new A(); for(int i=0;i<3;i++) { a.setI(i); list.add(A ...
- href和src的区别(小计)
1.Src 是指向物件的来源地址,请求src资源时会将其指向的资源下载并应用文档中 src的内容是页面上比不可少的一部分,是引入.在 img.script.iframe 等元素上使用. 2.href ...
- PAT (Basic Level) Practice (中文)1022 D进制的A+B
1022 D进制的A+B 输入两个非负 10 进制整数 A 和 B (≤2^30^−1),输出 A+B 的 D (1<D≤10)进制数. 输入格式: 输入在一行中依次给出 3 个整数 A.B 和 ...