3992: [SDOI2015]序列统计
3992: [SDOI2015]序列统计
分析:
给定一个集和s,求多少个长度为n的序列,满足序列中每个数都属于s,并且所有数的乘积模m等于x。
设$f=\sum\limits_{i=0}^{n - 1} a_i x ^ i \ \ 如果集合中存在i,a_i = 1$
那么答案的生成函数为f自乘n次,这里可以快速幂。这里"乘法"定义是:设多项式a乘多项式b等于c,$\sum\limits_{k=0}^{n - 1} c_k = \sum\limits_{i \times j = k} a_i \times b_j$ 每次“乘法”的复杂度是$m^2$,所以复杂度是$O(m^2logn)$。
考虑优化“乘法”的部分,我们知道多项式乘法利用FFT/NTT可以做到$nlogn$的,看能否转化为多项式乘法,即多项式乘法的定义变为$\sum\limits_{k=0}^{n - 1} c_k = \sum\limits_{i + j = k} a_i \times b_j$。
NTT中,有引入原根的概念,在NTT中,原根的用途相当于单位根。 原根有一个性质:对于mod p下的原根g,$g^1, g^2 \dots g^{p - 1}$互不相同,$g^{p - 1} \equiv 1 \mod p$。而且$g^1, g^2 \dots g^{p - 1}$可以分别表示$1,2 \dots p - 1$。
那么我们对m求出单位根,集合S中出现的每个数,都可以表示为$s_i = g^{t_{s_i}}$
此时对于原来的一个序列y,$\prod y_i = x \mod m$,就变成了$\prod g ^{t_{y_i}} = g^{t_x} \mod m$,即$\sum t_{y_i} = x \mod m - 1$
现在我们求的就是长度为n的序列,序列中每个数都属于集合t,并且所有数的和模(m-1)等于x 如此按照上面的做法,将乘法的定义改为多项式乘法的定义,快速幂+NTT即可复杂度$mlogmlogn$。
注意:多项式乘法中是没有取模的,而这里(i+j)%(m-1),直接将数组加倍,然后NTT完后,大于等于m的加到相应的模m后的位置上即可。
代码:
- #include<cstdio>
- #include<algorithm>
- #include<cstring>
- #include<iostream>
- #include<cmath>
- #include<cctype>
- #include<set>
- #include<queue>
- #include<vector>
- #include<map>
- using namespace std;
- typedef long long LL;
- inline int read() {
- int x=,f=;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-;
- for(;isdigit(ch);ch=getchar())x=x*+ch-'';return x*f;
- }
- const int mod = ;
- const int N = ;
- int vis[N], rev[N], n = , m;
- int f[N], g[N], a[N], b[N], inv;
- int ksm(int a,int b,int p) {
- a %= p;
- int ans = ;
- while (b) {
- if (b & ) ans = 1ll * ans * a % p;
- a = 1ll * a * a % p;
- b >>= ;
- }
- return ans % p;
- }
- int Calc(int x) {
- if (x == ) return ;
- for (int i = ; ; ++i) {
- bool flag = ;
- for (int j = ; j * j < x; ++j)
- if (ksm(i, (x - ) / j, x) == ) { flag = false; break; }
- if (flag) return i;
- }
- }
- void NTT(int *a,int n,int ty) {
- for (int i = ; i < n; ++i) if (i < rev[i]) swap(a[i], a[rev[i]]);
- for (int m = ; m <= n; m <<= ) {
- int w1 = ksm(, (mod - ) / m, mod);
- if (ty == -) w1 = ksm(w1, mod - , mod);
- for (int i = ; i < n; i += m) {
- int w = ;
- for (int k = ; k < (m >> ); ++k) {
- int u = a[i + k], t = 1ll * w * a[i + k + (m >> )] % mod;
- a[i + k] = (u + t) % mod;
- a[i + k + (m >> )] = (u - t + mod) % mod;
- w = 1ll * w * w1 % mod;
- }
- }
- }
- }
- void mul(int *g,int *f) {
- for (int i = ; i < n; ++i) a[i] = g[i] % mod, b[i] = f[i] % mod;
- NTT(a, n, );
- NTT(b, n, );
- for (int i = ; i < n; ++i) a[i] = 1ll * a[i] * b[i] % mod;
- NTT(a, n, -);
- for (int i = ; i < n; ++i) a[i] = 1ll * a[i] * inv % mod;
- for (int i = ; i < m - ; ++i) g[i] = (a[i] + a[i + m - ]) % mod;
- }
- void solve(int b) {
- inv = ksm(n, mod - , mod);
- g[] = ;
- while (b) {
- if (b & ) mul(g, f);
- b >>= ;
- mul(f, f);
- }
- }
- int main() {
- int cnt = read(); m = read(); int x = read(), s = read();
- for (int i = ; i <= s; ++i) vis[read()] = ;
- int q = Calc(m), pos = -, L = ;
- for (int i = , j = ; i < m - ; ++i, j = 1ll * j * q % m) {
- if (vis[j]) f[i] = ;
- if (j == x) pos = i;
- }
- int M = (m - ) * ;
- while (n < M) n <<= , L ++;
- for (int i = ; i < n; ++i) rev[i] = (rev[i >> ] >> ) | ((i & ) << (L - ));
- solve(cnt);
- if (pos != -) cout << g[pos] % mod;
- else cout << ;
- return ;
- }
3992: [SDOI2015]序列统计的更多相关文章
- BZOJ 3992: [SDOI2015]序列统计 [快速数论变换 生成函数 离散对数]
3992: [SDOI2015]序列统计 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 1017 Solved: 466[Submit][Statu ...
- [BZOJ 3992][SDOI2015]序列统计
3992: [SDOI2015]序列统计 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 2275 Solved: 1090[Submit][Stat ...
- BZOJ 3992: [SDOI2015]序列统计 NTT+快速幂
3992: [SDOI2015]序列统计 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 1155 Solved: 532[Submit][Statu ...
- BZOJ 3992: [SDOI2015]序列统计 快速幂+NTT(离散对数下)
3992: [SDOI2015]序列统计 Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S ...
- 【BZOJ】3992: [SDOI2015]序列统计 NTT+生成函数
[题意]给定一个[0,m-1]范围内的数字集合S,从中选择n个数字(可重复)构成序列.给定x,求序列所有数字乘积%m后为x的序列方案数%1004535809.1<=n<=10^9,3< ...
- bzoj 3992 [SDOI2015]序列统计——NTT(循环卷积&&快速幂)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3992 有转移次数.模M余数.方案数三个值,一看就是系数的地方放一个值.指数的地方放一个值.做 ...
- bzoj 3992 [SDOI2015] 序列统计 —— NTT (循环卷积+快速幂)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3992 (学习NTT:https://riteme.github.io/blog/2016-8 ...
- BZOJ.3992.[SDOI2015]序列统计(DP NTT 原根)
题目链接 \(Description\) 给定\(n,m,x\)和集合\(S\).求\(\prod_{i=1}^na_i\equiv x\ (mod\ m)\)的方案数.其中\(a_i\in S\). ...
- bzoj 3992: [SDOI2015]序列统计【原根+生成函数+NTT+快速幂】
还是没有理解透原根--题目提示其实挺明显的,M是质数,然后1<=x<=M-1 这种计数就容易想到生成函数,但是生成函数是加法,而这里是乘法,所以要想办法变成加法 首先因为0和任何数乘都是0 ...
随机推荐
- [WINDOWS MOBILE | SOLUTION] 通过有线连接到 PC 后,WM设备能 PING 通网关但是不能上网
在 Windows Mobile Device Center 处点击 Mobile Device Settings, Connection Settings, 选择 This computer con ...
- Redis搜索引擎设计
以下图片是基于自身对知识掌握的基本能力而画出的,并没有系统全面的读过活跃于互联网大牛的著作(个人认为那样会限制自身的思维空间),因此,若图片里存在错误,敬请批评指正,谢谢! 除非互联网项目,传统的制造 ...
- 关于sys CPU usage 100%问题的分析
最近一个客户抱怨他的核心EBS数据库出现性能问题.这是一个10.2.0.3的数据库,运行在Red Hat Enterprise Linux Server release 5.5 (Linux x86- ...
- Mysql5.7 的错误日志中最常见的note级别日志解释
在使用mysql5.7的时候,发现了不少在mysql5.6上不曾见过的日志,级别为note, 最常见的note日志以下三种,下面我们来逐个解释. 第一种,Aborted connectio ...
- Windows平台使用Gitblit搭建Git服务器教程
Windows平台使用Gitblit搭建Git服务器图文教程 Git服务现在独树一帜,相比与SVN有更多的灵活性,最流行的开源项目托管网站Github上面,如果托管开源项目,那么就是免费使用的,但是闭 ...
- Linux 系统学习梳理_【All】
第一部分---基础学习 00.Linux操作系统各版本ISO镜像下载 00.Linux系统下安装Vmware(虚拟机) 00.Linux 系统安装[Redhat] 00.Linux 系统安装[Cent ...
- .net mvc Html.DropDownListFor 设置默认值无效
错误描述: 控制器部分: //从数据字典中加载下拉框 (使用DropDownListFor,SelectList 中不需要设置选中值,即便设置了选中值,也会优先读取Model中对应的值) ViewBa ...
- Ubuntu下安装指定版本的mysql
1.编辑/etc/apt/sources.list和/etc/apt/sources.list.save, 手动加上deb http://archive.ubuntu.com/ubuntu trust ...
- September 28th 2017 Week 39th Thursday
Every saint has a past and every sinner has a future. 圣人皆有过去,罪人皆有未来. If you were a sinner in the pas ...
- java Date日期类和SimpleDateFormat日期类格式
~Date表示特定的时间,精确到毫秒~构造方法:public Date()//构造Date对象并初始化为当前系统的时间public Date(long date) //1970-1-1 0:0:0到指 ...