bzoj 3992 [SDOI2015]序列统计——NTT(循环卷积&&快速幂)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3992
有转移次数、模M余数、方案数三个值,一看就是系数的地方放一个值、指数的地方放一个值、做卷积的次数表示一个值(应该是表示转移次数)。
可以余数和方案数都要求相乘,指数只能相加,怎么办?
然后看题解,原来可以用M的原根的幂来表示余数那个信息!因为原根的几次幂和%M剩余类可以一一对应(除了%M==0!!!),所以用原根的幂表示%M余几,两个余数相乘就变成原根的指数相加了!把该余数对应的原根的指数放在多项式指数的位置,就可以NTT啦!
原根是 1~P-1 次幂的值%P各不相同的,所以可以用 0次项~M-2次项 或者 1次项~M-1 次项来表示。
n的范围要求快速幂。但不是把点值拿出来之后对点值快速幂一番再用点值还原回系数,因为每次卷积那个多项式的长度都要翻倍,所以最后n个点的个数就不够了。
所以要快速幂中每次卷积了一下后把它翻倍的长度手动循环一番变回原长M。这样就行啦!
注意数据范围!!!求的那个 x 不能为0,而给出的元素可以为0!而原根的那些幂都不会为0!(仔细一想,只有0或M的倍数才会%M==0)考虑到那个 x 不会为0、而数列中放入一个0的话值就变成0了,所以给出0以后要认为没有那个元素!!!!!
快速幂时,ans的初值应该像1一样;也就是一个多项式卷积它之后还是该多项式本身。想一想,就是在0次项赋1、其他项赋0即可。
发现>(M<<1)的项的值一定是0;所以循环的时候可以直接减掉1个(M-1)而不用模什么的。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=; const ll mod=;
int n,m,M,pn,s[N],zb[N],pri[N],len,r[N<<];
int a[N<<],ans[N<<];
int rdn()
{
int ret=;bool fx=;char ch=getchar();
while(ch>''||ch<''){if(ch=='-')fx=;ch=getchar();}
while(ch>=''&&ch<='') ret=(ret<<)+(ret<<)+ch-'',ch=getchar();
return fx?ret:-ret;
}
void upd(int &x,int md){x>=md?x-=md:;}
int pw(int x,int k,int md)
{int ret=;while(k){if(k&)ret=(ll)ret*x%md;x=(ll)x*x%md;k>>=;}return ret;}
int gtrt()
{
int k=M-,tot=;
for(int i=;i*i<=k;i++)
if(k%i==){pri[++tot]=i;while(k%i==)k/=i;}
if(k>)pri[++tot]=k;
for(int g=;;g++)
{
int i;
for(i=;i<=tot;i++)
if(pw(g,(M-)/pri[i],M)==)break;
if(i>tot)return g;
}
}
void ntt(int *a,bool fx)
{
for(int i=;i<len;i++)
if(i<r[i])swap(a[i],a[r[i]]);
for(int R=;R<=len;R<<=)
{
int m=R>>;
int Wn=pw(,(mod-)/R,mod);
fx?Wn=pw(Wn,mod-,mod):;
for(int i=;i<len;i+=R)
for(int j=,w=;j<m;j++,w=(ll)w*Wn%mod)
{
int tmp=(ll)w*a[i+m+j]%mod;
a[i+m+j]=a[i+j]+mod-tmp; upd(a[i+m+j],mod);
a[i+j]=a[i+j]+tmp; upd(a[i+j],mod);
}
}
if(!fx)return; int inv=pw(len,mod-,mod);
for(int i=;i<len;i++)a[i]=(ll)a[i]*inv%mod;
}
int main()
{
n=rdn(); M=rdn(); pn=rdn(); m=rdn();
for(int i=;i<=m;i++)s[i]=rdn();
int rt=gtrt();
for(int i=,k=rt;i<M;i++,k=k*rt%M) zb[k]=i;
len=;
for(;len<=M<<;len<<=);
for(int i=;i<len;i++)r[i]=(r[i>>]>>)+((i&)?len>>:); for(int i=;i<=m;i++)if(s[i])a[zb[s[i]]]=;////if
ans[]=;///
while(n)
{
ntt(a,);
if(n&)
{
ntt(ans,);
for(int i=;i<len;i++)ans[i]=(ll)ans[i]*a[i]%mod;
ntt(ans,);
for(int i=;i<M;i++)//pos which >(M<<1) surely have no value
ans[i]+=ans[i+M-],ans[i+M-]=,upd(ans[i],mod);
}
for(int i=;i<len;i++)a[i]=(ll)a[i]*a[i]%mod;
ntt(a,);
for(int i=;i<M;i++)
a[i]+=a[i+M-],a[i+M-]=,upd(a[i],mod);
n>>=;
}
printf("%d\n",ans[zb[pn]]);
return ;
}
bzoj 3992 [SDOI2015]序列统计——NTT(循环卷积&&快速幂)的更多相关文章
- bzoj 3992 [SDOI2015] 序列统计 —— NTT (循环卷积+快速幂)
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3992 (学习NTT:https://riteme.github.io/blog/2016-8 ...
- 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+原根
今天开始学习丧心病狂的多项式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\). ...
随机推荐
- 【HackerRank】Sherlock and MiniMax
题目连接:Sherlock and MiniMax Watson gives Sherlock an array A1,A2...AN. He asks him to find an integer ...
- CentOS 6.5 下vim 配置
1. 登录并进入你常用的用户名下,查看其主目录 命令: # su xxx $ cd xxx $ ls -a 2.查看并建立目录和文件 首先看你的主目录~/ 下是否有.vimrc文件,没有就输入指令 $ ...
- 四月兄弟AprilBeacon
硬件相关ibeacon https://www.aprbrother.com/
- Linux基本常用命令
说到Linux,它就是基于POSIX和UNIX的多用户,多任务,支持多线程和多CPU的操作系统.它能运行主要的UNIX的工具软件,应用程序和网络协议.它支持32位和64位硬件.linux继承Unix以 ...
- HMM简单理解(来自quora&其他网上资料)
转载自quora: 连接:https://www.quora.com/What-is-a-simple-explanation-of-the-Hidden-Markov-Model-algorithm ...
- oracle 字典表查询
1.oracle 字典表查询 /*显示当前用户*/ show user 在sql plus中可用,在pl sql中不可用 /*查看所有用户名*/ select username,user_id,cre ...
- 用javascript实现的验证码
<html xmlns="http://www.w3.org/1999/xhtml"><head runat="server"> ...
- 医院Android项目总结
Eclipse ADT 配置AVD 1.layout布局:xml 如ck_report.xml <Text view ...android:id="ck"> & ...
- 微信小程序申请。很蛋疼的流程。
微信小程序申请. 营业执照,食品许可证,身份证正面,身份证反面. 1.先要申请服务号. 需要一个QQ邮箱,申请服务号. 填写各种信息,营业执照信息. 法人信息. 管理员用自己人的.方便开发操作. 申请 ...
- nova rebuild
nova rebuild¶ usage: nova rebuild [--rebuild-password <rebuild-password>] [--poll] [--minimal] ...