bzoj 3992 [SDOI2015] 序列统计 —— NTT (循环卷积+快速幂)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3992
(学习NTT:https://riteme.github.io/blog/2016-8-22/ntt.html
https://www.cnblogs.com/Mychael/p/9297652.html
http://blog.miskcoo.com/2015/04/polynomial-multiplication-and-fast-fourier-transform#i-15 )
首先,如果把方案数和乘积分别放在系数和次数上,就可以用多项式做了;
方案数放在系数上好说,但次数是相加的,如何表示乘积?
考虑乘积与加法的关系 —— 幂的相乘就是指数相加;
所以可以找出乘积的模数 m 的原根,用其次数相加代表乘积,这个次数好像被称为“指标”;
构造出多项式,由于要取模,所以用 NTT 做;
也就是要把初始的多项式做 n 次幂,可以用快速幂,但注意累乘起来的是系数而不是点值;
指标从0开始或从1开始都可以,也就是把 0 次方作为 1 和把 m-1 次方作为 1 的区别,对应系数的时候要根据这个注意一下(代码中注释里的方案也可);
初始化一个多项式并不是把每个系数都赋值1!而只有第0项是1,这样别的多项式乘过来还是那个多项式;
然后要特别注意读入时去掉0!因为原根系列中没有模出0的,所以以原根为基础的 NTT 算的时候不能考虑0,而反正最后要求的方案中,x >= 1,一旦有0,乘积就是0了,所以0对答案没有影响,就当没给这个数算即可;
一下午的心血...
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int const xn=(<<),xm=,mod=;
int n,m,rev[xn],g,a[xn],b[xn],lim,r[xm],cnt,pri[xm],inv;
int rd()
{
int ret=,f=; char ch=getchar();
while(ch<''||ch>''){if(ch=='-')f=; ch=getchar();}
while(ch>=''&&ch<='')ret=(ret<<)+(ret<<)+ch-'',ch=getchar();
return f?ret:-ret;
}
int pw(ll a,int b,int md)
{
ll ret=;
for(;b;b>>=,a=(a*a)%md)if(b&)ret=(ret*a)%md;
return ret;
}
void div(int x)
{
for(int i=;i*i<=x;i++)
{
if(x%i)continue;
pri[++cnt]=i; while(x%i==)x/=i;
}
if(x>)pri[++cnt]=x;
}
void init()
{
lim=; int l=;
while(lim<=m+m)lim<<=,l++;
//while(lim<=2*(m-1))lim<<=1,l++;
for(int i=;i<lim;i++)
rev[i]=((rev[i>>]>>)|((i&)<<(l-)));
inv=pw(lim,mod-,mod); if(m==){g=; return;}
div(m-);
for(g=;;g++)
{
bool f=;
for(int j=;j<=cnt;j++)
if(pw(g,(m-)/pri[j],m)==){f=; break;}
if(!f)break;
}
for(int i=,k=g;i<m;i++,k=(ll)k*g%m)r[k]=i;
//for(int i=0,k=1;i<m-1;i++,k=(ll)k*g%m)r[k]=i;//k=1
}
int upt(int x){while(x>=mod)x-=mod; while(x<)x+=mod; return x;}
void ntt(int *a,int tp)
{
for(int i=;i<lim;i++)
if(i<rev[i])swap(a[i],a[rev[i]]);
for(int mid=;mid<lim;mid<<=)
{
int wn=pw(,(mod-)/(mid<<),mod);
if(tp==-)wn=pw(wn,mod-,mod);//
for(int j=,len=(mid<<);j<lim;j+=len)
{
int w=;
for(int k=;k<mid;k++,w=(ll)w*wn%mod)
{
int x=a[j+k],y=(ll)w*a[j+mid+k]%mod;
a[j+k]=upt(x+y); a[j+mid+k]=upt(x-y);
}
}
}
}
void pww()
{
ntt(a,);
for(int i=;i<lim;i++)a[i]=(ll)a[i]*a[i]%mod;
ntt(a,-);
for(int i=;i<lim;i++)a[i]=(ll)a[i]*inv%mod;
for(int i=m;i<lim;i++)a[i%m+]=upt(a[i%m+]+a[i]),a[i]=;//%m+1
//for(int i=m-1;i<lim;i++)a[i%(m-1)]=upt(a[i%(m-1)]+a[i]),a[i]=0;
}
void mul()
{
ntt(a,); ntt(b,);//
for(int i=;i<lim;i++)b[i]=(ll)b[i]*a[i]%mod;
ntt(a,-); ntt(b,-);//
for(int i=;i<lim;i++)
a[i]=(ll)a[i]*inv%mod,b[i]=(ll)b[i]*inv%mod; for(int i=m;i<lim;i++)
a[i%m+]=upt(a[i%m+]+a[i]),a[i]=,
b[i%m+]=upt(b[i%m+]+b[i]),b[i]=;
/*
for(int i=m-1;i<lim;i++)
a[i%(m-1)]=upt(a[i%(m-1)]+a[i]),a[i]=0,
b[i%(m-1)]=upt(b[i%(m-1)]+b[i]),b[i]=0;
*/
}
int main()
{
n=rd(); m=rd(); init();
int p=rd(),num=rd();
for(int i=,x;i<=num;i++)
{
x=rd();
if(x)a[r[x]]=;//x!=0 !!
}
int t=n;
//for(int i=0;i<lim;i++)b[i]=1;
b[]=;//!
for(;t;t>>=,pww())if(t&)mul();
printf("%d\n",b[r[p]]);
return ;
}
bzoj 3992 [SDOI2015] 序列统计 —— NTT (循环卷积+快速幂)的更多相关文章
- BZOJ 3992: [SDOI2015]序列统计 NTT+快速幂
3992: [SDOI2015]序列统计 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 1155 Solved: 532[Submit][Statu ...
- 【BZOJ3992】[SDOI2015]序列统计 NTT+多项式快速幂
[BZOJ3992][SDOI2015]序列统计 Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属 ...
- bzoj 3992 [SDOI2015]序列统计——NTT(循环卷积&&快速幂)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3992 有转移次数.模M余数.方案数三个值,一看就是系数的地方放一个值.指数的地方放一个值.做 ...
- bzoj 3992: [SDOI2015]序列统计 NTT+原根
今天开始学习丧心病狂的多项式qaq...... . code: #include <bits/stdc++.h> #define ll long long #define setIO ...
- BZOJ 3992: [SDOI2015]序列统计 快速幂+NTT(离散对数下)
3992: [SDOI2015]序列统计 Description 小C有一个集合S,里面的元素都是小于M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数列中的每个数都属于集合S ...
- BZOJ 3992: [SDOI2015]序列统计 [快速数论变换 生成函数 离散对数]
3992: [SDOI2015]序列统计 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 1017 Solved: 466[Submit][Statu ...
- [BZOJ 3992][SDOI2015]序列统计
3992: [SDOI2015]序列统计 Time Limit: 30 Sec Memory Limit: 128 MBSubmit: 2275 Solved: 1090[Submit][Stat ...
- bzoj 3992: [SDOI2015]序列统计【原根+生成函数+NTT+快速幂】
还是没有理解透原根--题目提示其实挺明显的,M是质数,然后1<=x<=M-1 这种计数就容易想到生成函数,但是生成函数是加法,而这里是乘法,所以要想办法变成加法 首先因为0和任何数乘都是0 ...
- BZOJ.3992.[SDOI2015]序列统计(DP NTT 原根)
题目链接 \(Description\) 给定\(n,m,x\)和集合\(S\).求\(\prod_{i=1}^na_i\equiv x\ (mod\ m)\)的方案数.其中\(a_i\in S\). ...
随机推荐
- Spring核心(ioc控制反转)
IoC,Inversion Of Control 即控制反转,由容器来管理业务对象之间的依赖关系,而非传统方式中的由代码来管理. 其本质.即将控制权由应用程序代码转到了外部容器,控制权的转移就是 ...
- visual c++ 2013进行MySQL编程(ODBC) -- (一) 套装安装
最近写了有些技术类文章了,只因为最近研究多了些东西,有一些项目用到了,所以自己记录一下,怕自己忘记,如果有哪位同学有自己的见解,可以邮件或者回复,技术类的探讨,不管对否,都是欢迎的. 操作之前,必须安 ...
- java实验8-Java输入输出流
1 读写文件 [实验目的] (1)掌握文本文件的读写方法. (2)掌握随机文件的读写方法. (3)掌握InputStream.OutputStream抽象类的基本使用. (4)掌握FileInputS ...
- C++11 并发指南五(std::condition_variable 详解)(转)
前面三讲<C++11 并发指南二(std::thread 详解)>,<C++11 并发指南三(std::mutex 详解)>分别介绍了 std::thread,std::mut ...
- Twitter网站架构分析介绍
http://www.kaiyuanba.cn/html/1/131/147/7539.htm作为140个字的缔造者,twitter太简单了,又太复杂了,简单是因为仅仅用140个字居然使有几次世界性事 ...
- Cadence SPB 16. 6 安装步骤
1.首先下载Cadence Allegro SPB orCAD16. 6 安装包,单击我,下载之后运行其中的setup.exe,然后先安装第一项License Manager
- FastDFS的配置、部署与API使用解读(8)FastDFS多种文件上传接口详解(转)
1.StorageClient与StorageClient1的区别 相信使用happy_fish的FastDFS的童鞋们,一定都熟悉StorageClient了,或者你熟悉的是StorageClien ...
- PHP debug_backtrace() 函数
PHP Error 和 Logging 函数 实例 生成 PHP backtrace: <?php function a($txt) { b("Glenn"); } func ...
- 命令行查看memcached的运行状态(转载)
很多时候需要监控服务器上的Memcached运行情况,比如缓存的查询次数,命中率之类的.但找到的那个memcached-tool是linux下用perl写的,我也没试过windows能不能用.后来发现 ...
- 模式识别之ocr项目---(模板匹配&BP神经网络训练)
摘 要 在MATLAB环境下利用USB摄像头采集字符图像,读取一帧保存为图像,然后对读取保存的字符图像,灰度化,二值化,在此基础上做倾斜矫正,对矫正的图像进行滤波平滑处理,然后对字符区域进行提取分割出 ...