题面

题解

设 \(f[i][j]\) 代表长度为 \(i\) 的序列, 乘积模 \(m\) 为 \(j\) 的序列有多少个

转移方程如下

\[f[i + j][C] = \sum_{A*B\equiv C \pmod{m} }f[i][B] * f[j][A]
\]

复杂度是 \(O(nm^2)\) 的

考虑倍增, 用类似快速幂那样的东西

\[f[2 * i][C] = \sum_{A*B\equiv C \pmod{m} }f[i][B] * f[i][A]
\]

恩, 复杂度变为了 \(O(m^2logn)\) 的

继续优化

上式相当于一个东西, 看到这个地方

\[c[z] = \sum_{x*y \equiv z \pmod m}a[x]b[y]
\]

如果是这样一种形式

\[c[z] = \sum_{x+y=z}a[x]b[y]
\]

我们就可以用 NTT 优化了

我们知道对数可以把乘法转成加法

但是对数是一个实数, 我们需要考虑一个模意义下的对数

把原根当做底数就可以了, 于是我们将上式转化为

\[c[log_gz] = \sum_{log_gx+log_gy\equiv log_gz\pmod m}a[log_gx]b[log_gy]
\]

考虑到 \(log_gx+log_gy\) 可能会大于 \(m\)

但是它一定不会大于 \(2m\) , 所以我们对于 \(c[z]\) 这个位置, 加上 \(c[z + m - 1]\) , 再将 \(c[z + m - 1]\) 清零即可

Code

#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <map>
const int N = 40005;
const int mod = 1004535809;
using namespace std; int n, m, X, S, lim, cnt, r[N], g, gg, a[N], b[N], res[N], f[N], top, fact[20005];
map<int, int> mp; template < typename T >
inline T read()
{
T x = 0, w = 1; char c = getchar();
while(c < '0' || c > '9') { if(c == '-') w = -1; c = getchar(); }
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * w;
} int fpow(int x, int y, int p)
{
int res = 1;
for( ; y; y >>= 1, x = 1ll * x * x % p)
if(y & 1) res = 1ll * res * x % p;
return res;
} int getroot(int x)
{
top = 0;
int rem = x - 1, p = rem;
for(int i = 2; i * i <= x; i++)
if(!(rem % i))
{
fact[++top] = i;
while(!(rem % i)) rem /= i;
}
if(rem > 1) fact[++top] = rem;
for(int flag = 1, i = 2; i <= p; i++, flag = 1)
{
for(int j = 1; j <= top && flag; j++)
if(fpow(i, p / fact[j], x) == 1) flag = 0;
if(flag) return i;
}
return -1;
} void ntt(int *p, int opt)
{
for(int i = 0; i < lim; i++) if(i < r[i]) swap(p[i], p[r[i]]);
for(int i = 1; i < lim; i <<= 1)
{
int rt = fpow(opt == 1 ? g : gg, (mod - 1) / (i << 1), mod);
for(int j = 0; j < lim; j += (i << 1))
{
int w = 1;
for(int k = j; k < j + i; k++, w = 1ll * w * rt % mod)
{
int x = p[k], y = 1ll * w * p[k + i] % mod;
p[k] = (1ll * x + y) % mod, p[k + i] = (1ll * x - y + mod) % mod;
}
}
}
if(opt == -1)
{
int inv = fpow(lim, mod - 2, mod);
for(int i = 0; i < lim; i++) a[i] = 1ll * a[i] * inv % mod;
}
} void mul(int *A, int *B, int *C)
{
for(int i = 0; i < lim; i++) a[i] = A[i], b[i] = B[i];
ntt(a, 1), ntt(b, 1);
for(int i = 0; i < lim; i++) a[i] = 1ll * a[i] * b[i] % mod;
ntt(a, -1);
for(int i = 0; i < m - 1; i++) a[i] = (1ll * a[i] + a[i + m - 1]) % mod, a[i + m - 1] = 0;
for(int i = 0; i < lim; i++) C[i] = a[i];
} int main()
{
n = read <int> (), m = read <int> (), X = read <int> (), S = read <int> ();
g = getroot(m), gg = fpow(g, m - 2, m);
for(int tmp = 1, i = 0; i < m - 1; i++, tmp = 1ll * tmp * g % m) mp[tmp] = i;
for(int x, i = 1; i <= S; i++)
{
x = read <int> ();
if(x) f[mp[x]]++;
}
res[mp[1]] = 1;
for(lim = 1; lim <= 2 * m; lim <<= 1, cnt++); cnt--;
for(int i = 0; i < lim; i++) r[i] = (r[i >> 1] >> 1) | ((i & 1) << cnt);
g = getroot(mod), gg = fpow(g, mod - 2, mod);
while(n)
{
if(n & 1) mul(res, f, res);
mul(f, f, f);
n >>= 1;
}
printf("%d\n", res[mp[X]]);
return 0;
}

[题解] [SDOI2015] 序列统计的更多相关文章

  1. 【题解】SDOI2015序列统计

    [题解]SDOI2015序列统计 来自永不AFO的YYB的推荐 这里是乘积,比较麻烦,不过由于给定的序列膜数是个小质数,所以可以\(O(m^2\log m)\)找原跟(实际上不需要这么多). 乘积有点 ...

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

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

  3. 【LG3321】[SDOI2015]序列统计

    [LG3321][SDOI2015]序列统计 题面 洛谷 题解 前置芝士:原根 我们先看一下对于一个数\(p\),它的原根\(g\)有什么性质(好像就是定义): \(g^0\%p,g^1\%p,g^2 ...

  4. 【BZOJ3992】[SDOI2015]序列统计 NTT+多项式快速幂

    [BZOJ3992][SDOI2015]序列统计 Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属 ...

  5. BZOJ 3992: [SDOI2015]序列统计 快速幂+NTT(离散对数下)

    3992: [SDOI2015]序列统计 Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S ...

  6. BZOJ 3992: [SDOI2015]序列统计 [快速数论变换 生成函数 离散对数]

    3992: [SDOI2015]序列统计 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1017  Solved: 466[Submit][Statu ...

  7. [SDOI2015]序列统计

    [SDOI2015]序列统计 标签: NTT 快速幂 Description 给你一个模m意义下的数集,需要用这个数集生成一个数列,使得这个数列在的乘积为x. 问方案数模\(1004535809\). ...

  8. 3992: [SDOI2015]序列统计

    3992: [SDOI2015]序列统计 链接 分析: 给定一个集和s,求多少个长度为n的序列,满足序列中每个数都属于s,并且所有数的乘积模m等于x. 设$f=\sum\limits_{i=0}^{n ...

  9. [BZOJ3992][SDOI2015]序列统计(DP+原根+NTT)

    3992: [SDOI2015]序列统计 Time Limit: 30 Sec  Memory Limit: 128 MBSubmit: 1888  Solved: 898[Submit][Statu ...

随机推荐

  1. SQL查询月、天、周、年(MySql的实例对比)

    SQL Server实现 日期部分 缩写 year yy, yyyy quarter qq, q month mm, m dayofyear dy, y day dd, d week wk, ww w ...

  2. ES6箭头函数及this指向

    箭头函数(=>):函数简写 无参数:() => {} 单个参数:x => {} 多个参数:(x, y) => {} 解构参数:({x, y}) => {} 嵌套使用:部署 ...

  3. Java 面向对象(五)抽象

    一.抽象概述 1.由来 父类中的方法,被它的子类们重写,子类各自的实现都不尽相同.那么父类的方法声明和方法主体,只有声明还有意义,而方法主体则没有存在的意义了. 我们把没有方法主体的方法称为抽象方法. ...

  4. C++ 函数重载二义性

    说起函数重载,我不由得想起了C++的“多态”特性.多态又分为静态(编译时)多态和动态(运行时)多态,静态多态即为函数重载,动态多态则是虚函数机制.虚函数水较深,先不讨论,今天我们来看一下函数重载.作用 ...

  5. SpringCloud之Zuul网关原理及其配置

    Zuul是spring cloud中的微服务网关.网关: 是一个网络整体系统中的前置门户入口.请求首先通过网关,进行路径的路由,定位到具体的服务节点上. Zuul是一个微服务网关,首先是一个微服务.也 ...

  6. 检测jquery是否正确引入

    if(typeof(jQuery)=="undefined"){ alert("jQuery is not imported"); }else{ alert(& ...

  7. Computer Vision_33_SIFT:Distinctive Image Features from Scale-Invariant Keypoints——2004

    此部分是计算机视觉部分,主要侧重在底层特征提取,视频分析,跟踪,目标检测和识别方面等方面.对于自己不太熟悉的领域比如摄像机标定和立体视觉,仅仅列出上google上引用次数比较多的文献.有一些刚刚出版的 ...

  8. 关闭安装包更新使用YUM在Linux中(RHEL / CentOS / Fedora)

    YUM (Yellowdog Updater Modified)  是一个开源的命令行工具,以及基于图形的软件包管理工具, 用于基于 RPM (RedHat Package Manager) 的 Li ...

  9. Http 缓存剖析

    缓存一直是前端优化的主战场, 利用好缓存就成功了一半. 本篇从http请求和响应的头域入手, 让你对浏览器缓存有个整体的概念. 最终你会发现强缓存, 协商缓存 和 启发式缓存是如此的简单. 导读 浏览 ...

  10. halcon基础数据类型详解

    #if defined(__CHAR_UNSIGNED__) || defined(__sgi) #define INT1 signed char /* integer, signed 1 Byte ...