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. Linux之virtualbox中的ubuntu虚拟机linux系统共享文件夹

    windows通过virtualbox软件与linux系统机型文件共享 1.第一步 在设置中找到共享文件夹选项,选择添加共享文件夹 2.第二步 选择需要与linux进行共享的文件夹,并选择固定分配 3 ...

  2. 一个好用的ssh终端:MobaXterm

    WSL由于没有图形界面,所有操作都是在命令行里执行,平时用来编译和跑CFD代码其实还是挺方便.不过有时候要查看WSL里的文件就比较麻烦,这时可以用SFTP这类工具,连接过去后直接操作文件.试过几个这类 ...

  3. Linux终端没有GUI,使用matplotlib绘图

    一.解决警告信息 ... _tkinter.TclError: no display name and no $DISPLAY environment variable 两种解决方法: 1.pytho ...

  4. Mac 10.12安装Windows远程桌面工具Microsoft Remote Desktop

    说明:之前Office自带的Windows远程桌面工具虽然简便,但是保存的服务器列表有限.而这个微软推出的自家工具可以完美解决这些问题. 下载: (链接:https://pan.baidu.com/s ...

  5. (转载)IDEA新建项目时,没有Spring Initializr选项

    最近开始使用IDEA作为开发工具,然后也是打算开始学习使用spring boot. 看着博客来进行操作上手spring boot,很多都是说 创建一个新项目(Create New Project) 选 ...

  6. 关于c#中委托与事件的一些理解

    文章目的:作者(初学者)在学习c#的过程中,对事件.委托及其中的“object sender,EventArgs e”一直感觉理解不透,因此在网上找了一些资料,学习并整理出了该篇笔记,希望能将自己的心 ...

  7. javascript全局方法与变量

    1.encodeURI(URI) a.作用:是对统一资源标识符(URI)进行编码的方法: b.参数:是一个完整的URI: c.特点:不需要对保留字以及在URI中有特殊意思的字符进行编码. (1).保留 ...

  8. ie和火狐事件addEventListener()及attachEvent()区别分析

    Mozilla中: addEventListener的使用方式: target.addEventListener(type, listener, useCapture); target: 文档节点.d ...

  9. MultipartFile的使用小结

    Multipartfile转File?File转MultipartFile?可千万别转晕了. 题图:from Google 1. MultipartFile类型转File类型 想要将Multipart ...

  10. MySQL Group Replication 介绍

    2016-12-12,一个重要的日子,mysql5.7.17 GA版发布,正式推出Group Replication(组复制) 插件,通过这个插件增强了MySQL原有的高可用方案(原有的Replica ...