http://www.lydsy.com/JudgeOnline/problem.php?id=3992



很容易得出DP方程:

f[i][c]=f[i-1][a]*f[1][b]①

其中a*b%M=c

f第一位为当前数列长度,第二维为当前数列模M意义下的乘积

考虑从一开始就剔除第二维为0的情况——把它单独考虑,一来她好算,二来她不影响其他结果

若将f[i-1][a]展开;

则:

$$f[i][c]=\sum_{a_1=1}^M\sum_{a_2=1}^M...\sum_{a_i=1}^M([\Pi_{j=1}^ia_j(mod)M=c]\Pi_{j=1}^if[1][a_j])$$②

把f[1]的所有第二维取值得出的结果构造为多项式,记为$f_1(x)$

$$f_1(x)=map[0]x^0+map[1]x^1+map[2]x^2...map[m-1]x^{m-1}$$③

其中,map[i]为i数字在S中出现的次数,同样的,map[i]=f[1][i]

于是:

$$f_i(x)=\sum_{j=1}^{m-1}a_{i,j}*x^j$$④

其中$$a_{i,j}=\sum_{x=kj}\sum_{d|x}a_{i-1,d}*a_{1,{x \over d}}$$

当然$a_{x,y}=f[x][y]$

于是发现①,是多项式在模意义下的狄利克雷卷积;

而②,则是其在模意义下的狄利克雷卷积的乘幂

然而这个东西不能快速运算;

尝试转换这些式子;

看①,发现c取值在1到M-1之间,而$g^x$(其中g为M的原根)在x取0到M-2时可取遍1到M-1

不妨依此改写①

设$g^{e_x}=x$

$$f[i][g^{e_c}]=f[i-1][g^{e_a}]*f[1][g^{e_b}],e_c=(e_a+e_b)(mod)(M-1)$$

$$ff[i][e_c]=ff[i-1][e_a]*f[1][e_b],e_c=(e_a+e_b)(mod)(M-1)$$⑤

ff与f同构,求f[i][x]等价于求ff[i][e_x];

于是发现⑤,是多项式在模意义下的卷积;

NTT计算,加多项式取模;

如果把ff写成类似f的②的形式,则他是多项式在模意义下的卷积的乘幂;

快速幂优化

总效率$O(M*log_2M*log_2N)$

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#define LL long long
using namespace std;
const LL mod=;
int N,M,X,S,len;
int rat[],map[],b[];
LL a[],ans[],g[],aa[];
LL Sqr_num(LL ,int );
void get_b(int );
void Sqr(int );
void pol_mul(LL a[],LL b[]);
int get_len(int );
void ra(LL f[]);
void NTT(LL f[],int t);
int main(){
int i,j,k;
scanf("%d%d%d%d",&N,&M,&X,&S);
for(i=;i<=S;i++){
scanf("%d",&j);
map[j]++;
}
if(X==){
printf("%lld",(Sqr_num(S,N)+mod-Sqr_num(S-map[],N))%mod);
return ;
}
get_b(M);M--;
for(i=;i<=M;i++)
a[b[i]%(M)]=map[i]%mod;
Sqr(N);
printf("%lld",ans[b[X]%M]);
return ;
}
LL Sqr_num(LL x,int n){
LL ret=;
while(n){
if(n&)(ret*=x)%=mod;
n>>=;(x*=x)%=mod;
}
return ret;
}
void get_b(int p){
int i,j,f=,ij,g;
for(i=;i<p;i++){
ij=;f=;
for(j=;j<p;j++){
(ij*=i)%=p;
if(j!=p-&&ij%p==)
break;
else
if(j==p-&&ij%p==)
f=;
}
if(f){
g=i;break;
}
}
ij=;
for(i=;i<p;i++){
(ij*=g)%=p;
b[ij]=i;
}
}
void Sqr(int n){
int i,fl=;
len=get_len(M);
rat[]=;
for(i=;i<len;i++)
rat[i]=rat[i>>]>>|((i&)*(len>>));
while(n){
if(n&){
if(!fl){
for(i=;i<M;i++)ans[i]=a[i];
fl=;
}
else
pol_mul(ans,a);
}
n>>=;
for(i=;i<M;i++)
aa[i]=a[i];
pol_mul(a,aa);
}
}
void pol_mul(LL a[],LL b[]){
int i,j,k;
for(i=M;i<len;i++)
a[i]=,b[i]=;
NTT(a,);NTT(b,);
for(i=;i<len;i++)
a[i]=a[i]*b[i]%mod;
NTT(a,-);NTT(b,-);
for(i=;i<M;i++)
a[i]=(a[i]+a[i+M])%mod;
}
int get_len(int n){
int ret=;
while(ret<(n<<))ret<<=;
return ret;
}
void ra(LL f[]){
int i;
for(i=;i<len;i++)
if(rat[i]>i)
swap(f[i],f[rat[i]]);
}
void NTT(LL f[],int t){
int i,j,k,lim;
int f0,f1;
ra(f);
for(k=;k<=len;k<<=){
lim=k>>;
g[]=;
g[]=Sqr_num(,t>?(mod-)/k:mod--(mod-)/k);
for(i=;i<lim;i++)
g[i]=g[i-]*g[]%mod;
for(i=;i<len;i+=k){
for(j=i;j<i+lim;j++){
f0=f[j];f1=g[j-i]*f[j+lim]%mod;
f[j]=(f0+f1)%mod;f[j+lim]=(f0-f1+mod)%mod;
}
}
}
if(t<){
LL inv=Sqr_num(len,mod-);
for(i=;i<len;i++)
(f[i]*=inv)%=mod;
}
}

[SD2015]序列统计——solution的更多相关文章

  1. [SDOI2015]序列统计

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

  2. Bzoj 4403: 序列统计 Lucas定理,组合数学,数论

    4403: 序列统计 Time Limit: 3 Sec  Memory Limit: 128 MBSubmit: 328  Solved: 162[Submit][Status][Discuss] ...

  3. BZOJ4403 序列统计—Lucas你好

    绝对是全网写的最详细的一篇题解  题目:序列统计 代码难度:简单 思维难度:提高+-省选 讲下题面:给定三个正整数N.L和R,统计长度在1到N之间,元素大小都在L到R之间的单调不降序列的数量.输出答案 ...

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

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

  5. 【BZOJ3992】序列统计(动态规划,NTT)

    [BZOJ3992]序列统计(动态规划,NTT) 题面 BZOJ 题解 最裸的暴力 设\(f[i][j]\)表示前\(i\)个数,积在膜意义下是\(j\)的方案数 转移的话,每次枚举一个数,直接丢进去 ...

  6. 【BZOJ4403】序列统计(组合数学,卢卡斯定理)

    [BZOJ4403]序列统计(组合数学,卢卡斯定理) 题面 Description 给定三个正整数N.L和R,统计长度在1到N之间,元素大小都在L到R之间的单调不降序列的数量.输出答案对10^6+3取 ...

  7. BZOJ 3992 【SDOI2015】 序列统计

    题目链接:序列统计 我来复习板子了……这道题也是我写的第一发求原根啊? 求原根方法: 从小到大依次枚举原根.设当前枚举的原根为\(x\),模数为\(p\),\(p-1\)的质因数分别为\(p_1,p_ ...

  8. bzoj 4403 序列统计 卢卡斯定理

    4403:序列统计 Time Limit: 3 Sec  Memory Limit: 128 MB Description 给定三个正整数N.L和R,统计长度在1到N之间,元素大小都在L到R之间的单调 ...

  9. 3992: [SDOI2015]序列统计

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

随机推荐

  1. JS正则表达式端口号,IP地址

    端口号:65535 正则:/^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6 ...

  2. js img转换base64

    方法一:canvas <script type="text/javascript"> function getBase64Image(img) { var canvas ...

  3. [转] Akka 使用系列之二: 测试

    [From] http://www.algorithmdog.com/akka-test 通过上一篇文章,我们已经大致了解怎么使用 Akka,期待细致用法.这篇文章将介绍如何用 Akka-testki ...

  4. System Verilog基础(二)

    这一篇笔记主要记录Procedural,Process,Task and function,Interface和Communication中值得注意的点. 1.Procedural 写testbenc ...

  5. 查看哪个用户、IP、什么时间登陆过服务器

    2019-01-07 utmpdump /var/log/wtmp 或者 who /var/log/wtmp

  6. Android事件分发和消费机制(转载)

    原文链接:http://www.cnblogs.com/sunzn/archive/2013/05/10/3064129.html Android 中与 Touch 事件相关的方法包括:dispatc ...

  7. Android动画及滑动事件冲突解决(转载)

    原文链接:http://blog.csdn.net/singwhatiwanna/article/details/38168103 Android开发中动画和事件处理是程序员迈向高手的必经之路,也是重 ...

  8. Mac下的SSH插件(默认自带)

    Mac下默认自带,直接通过终端输入ssh获取更多的参数帮助.

  9. (转)rsync+inotify实时同步

    原文:http://lxw66.blog.51cto.com/5547576/1331048 声明:rsync inotify 需要逆向思考,当只做rsync不实时同步时,我们一般是从rsync服务端 ...

  10. 释放linux端口

    感谢作者的共享,在此表示感谢 有时候关闭软件后,后台进程死掉,导致端口被占用.下面以TOMCAT端口8060被占用为例,列出详细解决过程. 解决方法: 1.查找被占用的端口 netstat -tln ...