LuoGuP3321:[SDOI2015]序列统计
Posted chitongz
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LuoGuP3321:[SDOI2015]序列统计相关的知识,希望对你有一定的参考价值。
Pre
错误百出。
第一次打多项式快速幂。
Solution
可以发现用多项式优化动态规划的转移。
每加入一个数,就乘上一个多项式(其实这个多项式有一点像生成函数,指数表示的数模意义下的值,系数表示的是方案的数量)。
这样就可以用多项式快速幂优化了。
于是我就\(WA\)了一发。
设\(f(i,j)\)表示已经有\(i\)个数,并且指数为\(j\)的时候的系数值。
\(f(i,j)-\sum\limits_m*n=jf(i-1,m)*f(i-1,n)\)
于是貌似不可做。
我尝试着从修改\(NTT\)的运算过程的角度思考,但是失败了。
看题解发现
敲黑板重点
设\(g\)是\(m\)的原根
\(f(i,log_gj)=\sum\limits_loh_gm+log_gn=log_gjf(i-1,log_gm)*f(i-1,log_gn)\)
可做。
Code
#include <bits/stdc++.h>
#define xx first
#define yy second
#define ll long long
using namespace std;
const int N = 17000 + 5, mod = 1004535809;
int nn, nm, x, s, n, bit, rg;
int f[N], g[N], h[N], val[N], rev[N];
inline int solve (int);
inline int mul (int u, int v) return 1LL * u * v % mod;
inline int add (int u, int v) return u + v >= mod ? u + v - mod : u + v;
inline int mns (int u, int v) return u - v < 0 ? u - v + mod : u - v;
inline int qpow (int u, int v, int md) int tot = 1, base = u % md;while (v) if (v & 1) tot = 1LL * tot * base % md;base = 1LL * base * base % md;v >>= 1;return tot;
inline void solve2 ();
inline void ntt (int *a, bool flag)
for (int i = 0; i < n; ++i)
rev[i] = (rev[i >> 1] >> 1) | ((i & 1) << (bit - 1));
if (i > rev[i]) swap (a[i], a[rev[i]]);
for (int l = 2; l <= n; l <<= 1)
int wi = qpow (flag ? qpow (3, mod - 2, mod) : 3, (mod - 1) / l, mod);
int m = l / 2;
for (int *k = a; k != a + n; k += l)
int w = 1;
for (int i = 0; i < m; ++i)
int tmp = mul (k[i + m], w);
k[i + m] = mns (k[i], tmp);
k[i] = add (k[i], tmp);
w = mul (w, wi);
int inver = qpow (n, mod - 2, mod);
for (int i = 0; i < n && flag; ++i)
a[i] = mul (a[i], inver);
inline void work (int *a, int *b)
ntt (a, false);
ntt (b, false);
for (int i = 0; i < n; ++i) a[i] = mul (a[i], b[i]);
ntt (a, true);
ntt (b, true);
for (int i = nm - 1; i < (nm - 1) * 2; ++i) a[i - (nm - 1)] = add (a[i - (nm - 1)], a[i]), a[i] = 0;
inline void fpow (int k)
while (k)
if (k & 1) work (f, g);
for (int i = 0; i < n; ++i) h[i] = g[i];
work (g, h);
k >>= 1;
int main ()
scanf ("%d%d%d%d", &nn, &nm, &x, &s);
n = 1, bit = 0;
while (n <= nm - 1) n <<= 1, ++bit;
n <<= 1, ++bit;
rg = solve (nm);
solve2 ();
for (int i = 1; i <= s; ++i) int tmp; scanf ("%d", &tmp); if (tmp % nm == 0) continue; g[val[tmp % nm]]++;
f[val[1]] = 1;
fpow (nn);
printf ("%d\n", f[val[x]]);
return 0;
inline void solve2 ()
int tg = 1;
for (int i = 0; i < nm - 1; ++i)
val[tg] = i;
tg = 1LL * tg * rg % nm;
int q[N], top;
inline int solve (int p)
top = 0;
int x = p - 1;
for (int i = 2; i * i <= x; ++i)
if (x % i == 0)
q[++top] = i;
while (x % i == 0)
x /= i;
if (x > 1) q[++top] = x;
for (int i = 2; ; ++i)
bool flag = true;
for (int j = 1; j <= top; ++j)
if (qpow (i, (p - 1) / q[j], nm) == 1) flag = false;
if (flag)
return i;
Conclusion
即使看了题解也不能很快做出来。
首先注意多项式乘法,就是\(work()\)函数,一定要把\(b\)数组还原(可能就我一个人错吧);
其次注意求原根的时候
if (x > 1) q[++top] = x;
一定是\(>1\)
以上是关于LuoGuP3321:[SDOI2015]序列统计的主要内容,如果未能解决你的问题,请参考以下文章
luogu P3321 [SDOI2015]序列统计 FFT