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. 要back的题目 先立一个flag

    要back的题目 目标是全绿!back一题删一题! acmm7 1003 1004 acmm8 1003 1004 sysu20181013 Stat Origin Title Solved A Gy ...

  2. NYOJ 1237 最大岛屿 (深搜)

    题目链接 描述 神秘的海洋,惊险的探险之路,打捞海底宝藏,激烈的海战,海盗劫富等等.加勒比海盗,你知道吧?杰克船长驾驶着自己的的战船黑珍珠1号要征服各个海岛的海盜,最后成为海盗王.  这是一个由海洋. ...

  3. CCC2018游记

    day (-1) 晚上睡觉没盖被子 day 0  2018年2月13日 下午放学回来感到一阵头痛,一量体温结果发烧了,感觉很蓝瘦,居然在CCC前一天生病. 本来注册了账号想打practise的,结果又 ...

  4. MSSQL 构建临时表SQL

    declare @StartQuarter int declare @StartYear int declare @EndQuarter int declare @EndYear int declar ...

  5. 对vue中 默认的 config/index.js:配置的详细理解 -【以及webpack配置的理解】-config配置的目的都是为了服务webpack的配置,给不同的编译条件提供配置

    当我们需要和后台分离部署的时候,必须配置config/index.js: 用vue-cli 自动构建的目录里面  (环境变量及其基本变量的配置) var path = require('path') ...

  6. hdfs文件上传机制与namenode元数据管理机制

    1.hdfs文件上传机制 文件上传过程:   1.客户端想NameNode申请上传文件, 2.NameNode返回此次上传的分配DataNode情况给客户端 3.客户端开始依向dataName上传对应 ...

  7. 2018DDCTF Misc部分WP

    题目给出了这样一串字符:d4e8e1f4a0f7e1f3a0e6e1f3f4a1a0d4e8e5a0e6ece1e7a0e9f3baa0c4c4c3d4c6fbb9e1e6b3e3b9e4b3b7b7 ...

  8. /proc/diskstats文件注解

    /proc/diskstats 注解 今儿在准备利用shell监控磁盘读写次数等信息时,看到该文件,但是又不清楚每段的具体含义,这里备注下. 文件内容 [root@namenode proc]# ca ...

  9. Java 关于微信公众号支付总结附代码

    很多朋友第一次做微信支付的时候都有蒙,但当你完整的做一次就会发现其实并没有那么难 业务流程和应用场景官网有详细的说明:https://pay.weixin.qq.com/wiki/doc/api/js ...

  10. 【java报错】Unknown character set index for field '224' received from server.

    在捣腾免费数据库时,使用的一个数据库提供商的服务器使用utf8mb4编码,而我的jar包还是八百年前的.然后...然后就报错了... (1) MYSQL 5.5 之前, UTF8 编码只支持1-3个字 ...