您的位置:首页 > 其它

bzoj3992 [SDOI2015]序列统计

2017-05-01 11:30 399 查看
传送门:http://www.lydsy.com/JudgeOnline/problem.php?id=3992

【题解】

很容易得到一个dp但是复杂度不对

我们想到用原根把乘法改成加法。

然后a1a2...an=g^(b1+b2+...+bn)

我们找到g^k=x,那么就有b1+b2+...+bn=x(mod (m-1))(m-1就是phi(m))

考虑生成函数,那么即为生成函数的n次方 mod x^(m-1)中,k次项的系数。

注意这里的mod是要把后面半部分移到前面的。

这样就可以FFT了,复杂度O(mlognlogm)

# include <stdio.h>
# include <string.h>
# include <algorithm>
// # include <bits/stdc++.h>

using namespace std;

typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
const int M = 8000 + 10, N = 2e5 + 10;
const int mod = 1004535809;
const int G = 3;

# define RG register
# define ST static

int n, m, X, S;
int fp[M];

struct pa {
int a
;
} A, ans;

inline int pwr(int a, int b, int P) {
int ret = 1;
while(b) {
if(b&1) ret = 1ll * ret * a % P;
a = 1ll * a * a % P;
b >>= 1;
}
return ret;
}

int t[2333], tn=0;
inline int getprt(int m) {
tn = 0;
for (int i=2; i<m-1; ++i)
if((m-1)%i==0) t[++tn] = i;
for (int i=2; ; ++i) {
bool ok = 1;
for (int j=1; j<=tn; ++j)
if(pwr(i, t[j], m) == 1) {
ok = 0;
break;
}
if(ok) return i;
}
return -1;
}

namespace NTT {
const int M = 2e5 + 10;
int n, w[2][M], lst[M], invn;
inline void init(int _n) {
n = 1;
while(n < _n) n <<= 1;
w[0][0] = 1, w[1][0] = 1;
int g = pwr(G, (mod-1)/n, mod), invg = pwr(g, mod-2, mod);
for (int i=1; i<n; ++i) w[0][i] = 1ll * w[0][i-1] * g % mod, w[1][i] = 1ll * w[1][i-1] * invg % mod;
int len = 0;
while((1<<len) < n) ++len;
for (int i=0; i<n; ++i) {
int t = 0;
for (int j=0; j<len; ++j) if(i&(1<<j)) t |= (1<<(len-j-1));
lst[i] = t;
}
invn = pwr(n, mod-2, mod);
}
inline void DFT(int *a, int op) {
int *o = w[op];
for (int i=0; i<n; ++i) if(i < lst[i]) swap(a[i], a[lst[i]]);
for (int len=2; len<=n; len<<=1) {
int m = (len>>1);
for (int *p = a; p != a+n; p += len) {
for (int k=0; k<m; ++k) {
int t = 1ll * o[n/len*k] * p[k+m] % mod;
p[k+m] = p[k] - t; if(p[k+m] < 0) p[k+m] += mod;
p[k] = p[k] + t; if(p[k] >= mod) p[k] -= mod;
}
}
}
if(op) {
for (int i=0; i<n; ++i) a[i] = 1ll * a[i] * invn % mod;
}
}

inline void mul(int *x, pa A, pa B, int Mod) {
DFT(A.a, 0); DFT(B.a, 0);
for (int i=0; i<n; ++i) A.a[i] = 1ll * A.a[i] * B.a[i] % mod;
DFT(A.a, 1);
for (int i=0; i<n; ++i) x[i] = 0;
for (int i=0; i<n; ++i) {
int np = i % Mod;
x[np] = x[np] + A.a[i];
if(x[np] >= mod) x[np] -= mod;
}
}
}

int main() {
scanf("%d%d%d%d", &n, &m, &X, &S);
int gg = getprt(m), sum = 1;
for (int i=0; i<m-1; ++i) {
fp[sum] = i;
sum = 1ll * sum * gg % m;
}
for (int i=1, pt; i<=S; ++i) {
scanf("%d", &pt);
if(pt) A.a[fp[pt]] = ans.a[fp[pt]] = 1;
}

NTT::init(m+m);

--n;

while(n) {
if(n&1) NTT::mul(ans.a, ans, A, m-1);
NTT::mul(A.a, A, A, m-1);
n >>= 1;
}

//    printf("%d\n", fp[X]);

printf("%d\n", ans.a[fp[X]]);
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: