http://www.lydsy.com/JudgeOnline/problem.php?id=3992

这道题好难啊。

第一眼谁都能看出来是个dp,设\(f(i,j)\)表示转移到第i位时前i位的乘积模m等于j的方案数。

转移很显然啊\(f(i,j)=\sum_{x,y\in[0,m)}[xy\mod m=j]f(i-1,x)*f(i-1,y)\)。

这个下标是乘积取模的转移根本无法优化啊。

但注意到题目最下方说m是一个质数。。。

把x=0特判掉,剩下\(x\in[1,m-1)\)时把x转化为m的原根的幂次。

设m的原根为\(g_m\)。

那么\(f(i,g_m^j)=\sum_{x,y\in[0,m-1)}[(x+y)\mod m=j]f(i-1,g_m^x)*f(i-1,g_m^y)\)。

这样通过原根在[0,m-1)上的不重不漏的一一映射,乘积取模变成加法取模,化成了一个循环卷积的形式。

(话说看模数也知道是NTT啊qwq)循环卷积直接用NTT做就可以了。

但要做N次循环卷积,\(N\leq 10^9\)。。。

在外面套层快速幂就可以了O(∩_∩)O~~

快速幂套循环卷积的正确性?先不循环卷积然后再压成循环卷积就很好证明啊。不过也可以把快速幂看成一个倍增,每次合并两个dp数组之类的,正确性都显然啊qwq

注意数组不要开小!用于NTT的数组要开到2的幂次qwq

时间复杂度\(O(m^2+m\log m\log n)\)。

(看了Menci大大的博客,“把原根的幂次看成多项式的幂次,dp数组记录在系数里”这个东西还叫生成函数?)

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll; const int M = 8193;
const int g = 267198;
const int p = 1004535809; int nin; int ipow(int a, int b) {
int ret = 1, w = a;
while (b) {
if (b & 1) ret = 1ll * ret * w % p;
w = 1ll * w * w % p;
b >>= 1;
}
return ret;
} int da[M << 1], db[M << 1], dc[M << 1], rev[M << 1], nWN[15], WN[15], n, m, x, s, C; void DNT(int *a, int *A, int flag) {
int tmp = 1;
for (int i = 0; i < n; ++i) A[rev[i]] = a[i];
for (int len = 2; len <= n; len <<= 1, ++tmp) {
int mid = len >> 1, wn = flag == 1 ? WN[tmp] : nWN[tmp];
for (int i = 0; i < n; i += len) {
int w = 1;
for (int j = 0; j < mid; ++j) {
int t = A[i + j], u = 1ll * A[i + j + mid] * w % p;
A[i + j] = (t + u) % p;
A[i + j + mid] = (t - u + p) % p;
w = 1ll * w * wn % p;
}
}
} if (flag == -1)
for (int i = 0; i < n; ++i)
A[i] = 1ll * A[i] * nin % p;
} int top; void NTTsqr(int *a) {
DNT(a, da, 1);
for (int i = 0; i < n; ++i)
da[i] = 1ll * da[i] * da[i] % p;
DNT(da, a, -1);
for (int i = 0; i < top; ++i) {
(a[i] += a[i + top]) %= p;
a[i + top] = 0;
}
} void NTT(int *a, int *b) {
DNT(a, da, 1); DNT(b, db, 1);
for (int i = 0; i < n; ++i)
dc[i] = 1ll * da[i] * db[i] % p;
DNT(dc, a, -1);
for (int i = 0; i < top; ++i) {
(a[i] += a[i + top]) %= p;
a[i + top] = 0;
}
} void init() {
int tot = 0, num = top << 1;
while (num) {num >>= 1; ++tot;}
n = 1 << tot;
nin = ipow(n, p - 2); int res;
for (int i = 0; i < n; ++i) {
num = i; res = 0;
for (int j = 0; j < tot; ++j) {
res <<= 1;
if (num & 1) res |= 1;
num >>= 1;
}
rev[i] = res;
} WN[14] = g, nWN[14] = ipow(g , p - 2);
for (int i = 13; i >= 1; --i) {
WN[i] = 1ll * WN[i + 1] * WN[i + 1] % p;
nWN[i] = 1ll * nWN[i + 1] * nWN[i + 1] % p;
}
} bool shown[M];
int r[M << 1], ww[M << 1], c[M]; int main() {
scanf("%d%d%d%d", &C, &m, &x, &s); top = m - 1;
if (x == 0) {printf("%d\n", (ipow(m, n) - ipow(m - 1, n) + p) % p); return 0;}
int num;
for (int i = 2; i < m; ++i) {
int ret = 1; bool flag = true;
for (int j = 0; j < top; ++j) {
ret = 1ll * ret * i % m;
if (shown[ret]) {flag = false; break;}
shown[ret] = true;
} if (!flag || ret != 1) {
ret = 1;
for (int j = 0; j < top; ++j) {
ret = 1ll * ret * i % m;
if (shown[ret]) shown[ret] = false;
else break;
}
} else {
num = i;
break;
}
} int ret = 1;
for (int i = 0; i < top; ++i) {
c[ret] = i;
ret = 1ll * ret * num % m;
} init(); int tt;
for (int i = 1; i <= s; ++i) {
scanf("%d", &tt);
if (tt != 0) ww[c[tt]] = 1;
} r[0] = 1;
while (C) {
if (C & 1) NTT(r, ww);
NTTsqr(ww);
C >>= 1;
} printf("%d\n", r[c[x]]); return 0;
}

【BZOJ 3993】【SDOI 2015】序列统计的更多相关文章

  1. [BZOJ 3992] [SDOI 2015] 序列统计(DP+原根+NTT)

    [BZOJ 3992] [SDOI 2015] 序列统计(DP+原根+NTT) 题面 小C有一个集合S,里面的元素都是小于质数M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数 ...

  2. BZOJ 3992 [SDOI 2015] 序列统计 解题报告

    这个题最暴力的搞法就是这样的: 设 $Dp[i][j]$ 为前 $i$ 个数乘积为 $j$ 的方案数. 转移的话就不多说了哈... 当前复杂度 $O(nm^2)$ 注意到,$M$ 是个质数,就说明 $ ...

  3. [BZOJ 3992] [SDOI 2015] 序列统计

    Description 传送门 Solution [一] 设 \(f[i][j]\) 表示前 \(i\) 个数的乘积在模 \(p\) 意义下等于 \(j\) 的方案数,有 \[ f[i][j]=\su ...

  4. BZOJ 3993 [SDOI 2015] 星际战争 解题报告

    首先我们可以二分答案. 假设当前二分出来的答案是 $Ans$ ,那么我们考虑用网络流检验: 设武器为 $X$,第 $i$ 个武器的攻击力为 $B_i$: 设机器人为 $Y$,第 $i$ 个机器人的装甲 ...

  5. [SDOI 2015]序列统计

    Description 题库链接 给出集合 \(S\) ,元素都是小于 \(M\) 的非负整数.问能够生成出多少个长度为 \(N\) 的数列 \(A\) ,数列中的每个数都属于集合 \(S\) ,并且 ...

  6. 【BZOJ 4403】 4403: 序列统计 (卢卡斯定理)

    4403: 序列统计 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 653  Solved: 320 Description 给定三个正整数N.L和R, ...

  7. [BZOJ 4818] [SDOI 2017] 序列计数

    Description Alice想要得到一个长度为 \(n\) 的序列,序列中的数都是不超过 \(m\) 的正整数,而且这 \(n\) 个数的和是 \(p\) 的倍数. Alice还希望,这 \(n ...

  8. 【BZOJ】3992: [SDOI2015]序列统计 NTT+生成函数

    [题意]给定一个[0,m-1]范围内的数字集合S,从中选择n个数字(可重复)构成序列.给定x,求序列所有数字乘积%m后为x的序列方案数%1004535809.1<=n<=10^9,3< ...

  9. BZOJ 3990 [SDOI 2015] 排序 解题报告

    这个题哎呀...细节超级多... 首先,我猜了一个结论.如果有一种排序方案是可行的,假设这个方案是 $S$ . 那么我们把 $S$ 给任意重新排列之后,也必然可以构造出一组合法方案来. 于是我们就可以 ...

  10. [BZOJ 3992][SDOI2015]序列统计

    3992: [SDOI2015]序列统计 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 2275  Solved: 1090[Submit][Stat ...

随机推荐

  1. Codeforces Round #411 (Div. 2) A-F

    比赛时候切了A-E,fst了A Standings第一页只有三个人挂了A题,而我就是其中之一,真™开心啊蛤蛤蛤 A. Fake NP time limit per test 1 second memo ...

  2. 【51NOD-0】1008 N的阶乘 mod P

    [算法]简单数学 [题解]多项式展开:(a*b)%p=(a%p*b%p)%p #include<cstdio> #include<algorithm> #define rep( ...

  3. 所有和Java中代理有关的知识点都在这了。

    对于每一个Java开发来说,代理这个词或多或少都会听说过.你可能听到过的有代理模式.动态代理.反向代理等.那么,到底什么是代理,这么多代理又有什么区别呢.本文就来简要分析一下. 代理技术,其实不只是J ...

  4. NightMare2(SCU4527+dijkstra+二分)

    题目链接:http://acm.scu.edu.cn/soj/problem.action?id=4527 题目: 题意:最短路的每条边除了边权之外还会有一个限制(财富,身上带的财富大于这个值则不能通 ...

  5. HDU 1465 不容易系列之一 (错排公式+容斥)

    题目链接 Problem Description 大家常常感慨,要做好一件事情真的不容易,确实,失败比成功容易多了! 做好"一件"事情尚且不易,若想永远成功而总从不失败,那更是难上 ...

  6. sql server 在作业中 远程连接 oracle mysql sqlserver 数据库

    在作业中执行远程连接时,需要对本次作业执行的步骤指定特定用户 并且该用户必须拥有所需操作数据库的db_owner角色,和服务器sysadmin角色 在作业中执行远程连接时,需要做登录映射 下面是我在作 ...

  7. poj 3751 时间日期格式转换

    题目链接:http://poj.org/problem?id=3751 题目大意:按照要求的格式将输入的时间日期进行转化. #include <iostream> #include < ...

  8. java===java基础学习(14)---封装

    package dog; public class Demo4 { public static void main(String []args) { Worker w1= new Worker(&qu ...

  9. ftrace 简介【转】

    转自:http://www.ibm.com/developerworks/cn/linux/l-cn-ftrace/index.html Trace 对于软件的维护和性能分析至关重要,ftrace 是 ...

  10. 【bzoj4695】最假女选手

    zcy的励志故事.jpg 傻逼zcy突然想立一个flag,写一个segment-tree-beats的题娱乐一下 于是他就想起了这道题. 他打算今晚写完 然后光是写他就写的头昏脑涨,还犯了询问写反这种 ...