[SD2015]序列统计——solution
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的更多相关文章
- [SDOI2015]序列统计
[SDOI2015]序列统计 标签: NTT 快速幂 Description 给你一个模m意义下的数集,需要用这个数集生成一个数列,使得这个数列在的乘积为x. 问方案数模\(1004535809\). ...
- Bzoj 4403: 序列统计 Lucas定理,组合数学,数论
4403: 序列统计 Time Limit: 3 Sec Memory Limit: 128 MBSubmit: 328 Solved: 162[Submit][Status][Discuss] ...
- BZOJ4403 序列统计—Lucas你好
绝对是全网写的最详细的一篇题解 题目:序列统计 代码难度:简单 思维难度:提高+-省选 讲下题面:给定三个正整数N.L和R,统计长度在1到N之间,元素大小都在L到R之间的单调不降序列的数量.输出答案 ...
- BZOJ 3992: [SDOI2015]序列统计 [快速数论变换 生成函数 离散对数]
3992: [SDOI2015]序列统计 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 1017 Solved: 466[Submit][Statu ...
- 【BZOJ3992】序列统计(动态规划,NTT)
[BZOJ3992]序列统计(动态规划,NTT) 题面 BZOJ 题解 最裸的暴力 设\(f[i][j]\)表示前\(i\)个数,积在膜意义下是\(j\)的方案数 转移的话,每次枚举一个数,直接丢进去 ...
- 【BZOJ4403】序列统计(组合数学,卢卡斯定理)
[BZOJ4403]序列统计(组合数学,卢卡斯定理) 题面 Description 给定三个正整数N.L和R,统计长度在1到N之间,元素大小都在L到R之间的单调不降序列的数量.输出答案对10^6+3取 ...
- BZOJ 3992 【SDOI2015】 序列统计
题目链接:序列统计 我来复习板子了……这道题也是我写的第一发求原根啊? 求原根方法: 从小到大依次枚举原根.设当前枚举的原根为\(x\),模数为\(p\),\(p-1\)的质因数分别为\(p_1,p_ ...
- bzoj 4403 序列统计 卢卡斯定理
4403:序列统计 Time Limit: 3 Sec Memory Limit: 128 MB Description 给定三个正整数N.L和R,统计长度在1到N之间,元素大小都在L到R之间的单调 ...
- 3992: [SDOI2015]序列统计
3992: [SDOI2015]序列统计 链接 分析: 给定一个集和s,求多少个长度为n的序列,满足序列中每个数都属于s,并且所有数的乘积模m等于x. 设$f=\sum\limits_{i=0}^{n ...
随机推荐
- idea部署tomcat:tomee required to support ear/ejb de。。
要确定artifact 的type是使用的web application :exploded类型,使用javaee application :exploded就会报这个错误.
- leetcode-278-First Bad Version(注意不要上溢)
题目描述:(说明中有简单翻译) You are a product manager and currently leading a team to develop a new product. Unf ...
- 蓝牙4.0BLE抓包(一) - 搭建EN-Dongle工作环境 使用EN-Dongle抓包 nRF51822
版权声明:本文为博主原创文章,转载请注明作者和出处. 蓝牙4.0 BLE的开发过程中,使用抓包器进行抓包分析无疑会极大地提高我们的开发效率,同时能帮我们快速的定位问题.对于初学者 ...
- Luogu P1342 请柬 题解
差不多是Dijkstra的裸题吧... 这道题可以分为来回两个阶段. 去的时候很简单,直接用一次Dijkstra,然后统计答案. 回来的时候就有些巧妙了,虽然表面上是每个点回到起点,但是何尝不可将其看 ...
- hdu1024 Max Sum Plus Plus 滚动dp
Max Sum Plus Plus Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others ...
- Spring Boot遇到的某些问题
Spring Boot遇到的某些问题 1.关于templates的html包格式问题: <properties> <project.build.sourceEncoding>U ...
- Window.localStorage
博客园 https://www.cnblogs.com/st-leslie/p/5617130.html 参考文档 https://developer.mozilla.org/zh-CN/docs/W ...
- exe4j安装及注册
1 安装 1 下载 exe4j下载地址:http://www.ej-technologies.com/download/exe4j/files.php, 进入网址,选择需要的版本,点击下载就可以了. ...
- assert函数的用法
assert这个函数在php语言中是用来判断一个表达式是否成立.返回true or false; 例如: <?php $s = 123; assert("is_int($s)" ...
- 用尾递归和普通递归实现n!算法,二者比较
尾递归 - Tail Recursion尾递归是针对传统的递归算法而言的, 传统的递归算法在很多时候被视为洪水猛兽. 它的名声狼籍, 好像永远和低效联系在一起.尾递归就是从最后开始计算, 每递归一次就 ...