洛谷P5282 【模板】快速阶乘算法(多项式多点求值+MTT)
题面
前置芝士
题解
这题法老当初好像讲过……而且他还说这种题目如果模数已经给定可以直接分段打表艹过去
以下是题解
我们设
\]
分治\(FFT\)即可求出
然后我们用多点求值求出\(x=1,s+1,2s+1,...,s^2-s+1\)时的答案
这样的话可以计算出\((s^2)!\),剩下没计算的部分直接暴力就是了
如果我们取\(s=\sqrt{n}\),复杂度大概就是\(O(s\log^2s)\)
以下是吐槽
啊……模数任意……没事把以前代码里都换成\(MTT\)就可以了
信心满满交上去发现只有\(40\)分
模数\(2e9\)?那两个数加起来都得爆\(int\)了啊……再改改……
交上去还是只有\(40\)分
突然想起来正常\(MTT\)的时候是取\(2^{15}\)的,然而这里值域可以达到\(2^{31}\),还是要炸啊……那么改成\(2^{16}\)好了
还是\(40\)分……
最后再仔细看了看,因为我多点求值的写法中最后小的部分是直接暴力秦九韶循环展开的,然后,四个\(p\times p\)级别的数加起来炸\(long\ long\)了……
强制定义一个\(__int128\)类型的\(0\)加上去……
终于\(A\)了……
ps:建议交之前测一下一下这组数据
\(p=2^{31}-1,n=p-1\),根据威尔逊定理有\(n!\equiv -1\pmod{p}\)
可以看看你到底炸了没有
upd:被\(shadowice\)巨巨的倍增吊打了QAQ(虽然也能\(A\)就是了),倍增的做法看这里(不知道比多点求值高到哪里去了)
//minamoto
#include<bits/stdc++.h>
#define R register
#define ll long long
#define III __int128
#define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
#define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
#define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
using namespace std;
const int N=(1<<17)+5;const double Pi=acos(-1.0);
int P;III zero;
inline int add(R int x,R int y){return 1ll*x+y>=P?1ll*x+y-P:x+y;}
inline int dec(R int x,R int y){return 1ll*x-y<0?1ll*x-y+P:x-y;}
inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
int ksm(R int x,R int y){
R int res=1;
for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
return res;
}
struct cp{
double x,y;
cp(){}
cp(R double xx,R double yy):x(xx),y(yy){}
inline cp operator +(const cp &b)const{return cp(x+b.x,y+b.y);}
inline cp operator -(const cp &b)const{return cp(x-b.x,y-b.y);}
inline cp operator *(const cp &b)const{return cp(x*b.x-y*b.y,x*b.y+y*b.x);}
inline cp operator *(const double &b)const{return cp(x*b,y*b);}
inline cp operator ~()const{return cp(x,-y);}
}w[2][N];
int r[21][N],lg[N];double inv[21];
void Pre(){
fp(d,0,17){
fp(i,1,(1<<d)-1)r[d][i]=(r[d][i>>1]>>1)|((i&1)<<(d-1));
lg[1<<d]=d,inv[d]=1.0/(1<<d);
}
for(R int i=1,d=0;i<131072;i<<=1,++d)fp(k,0,i-1){
w[1][i+k]=cp(cos(Pi*k*inv[d]),sin(Pi*k*inv[d])),
w[0][i+k]=cp(cos(Pi*k*inv[d]),-sin(Pi*k*inv[d]));
}
}
int lim,d;
void FFT(cp *A,int ty){
fp(i,0,lim-1)if(i<r[d][i])swap(A[i],A[r[d][i]]);
cp t;
for(R int mid=1;mid<lim;mid<<=1)
for(R int j=0;j<lim;j+=(mid<<1))
fp(k,0,mid-1)
A[j+k+mid]=A[j+k]-(t=A[j+k+mid]*w[ty][mid+k]),
A[j+k]=A[j+k]+t;
if(!ty)fp(i,0,lim-1)A[i]=A[i]*inv[d];
}
void MTT(int *a,int *b,int len,int *c){
static cp f[N],g[N],p[N],q[N];
lim=(len<<1),d=lg[lim];
fp(i,0,len-1)f[i]=cp(a[i]>>15,a[i]&32767),g[i]=cp(b[i]>>15,b[i]&32767);
fp(i,len,lim-1)f[i]=g[i]=cp(0,0);
FFT(f,1),FFT(g,1);
fp(i,0,lim-1){
cp t,f0,f1,g0,g1;
t=~f[i?lim-i:0],f0=(f[i]-t)*cp(0,-0.5),f1=(f[i]+t)*0.5;
t=~g[i?lim-i:0],g0=(g[i]-t)*cp(0,-0.5),g1=(g[i]+t)*0.5;
p[i]=f1*g1,q[i]=f1*g0+f0*g1+f0*g0*cp(0,1);
}
FFT(p,0),FFT(q,0);
fp(i,0,lim-1)c[i]=(((ll)(p[i].x+0.5)%P<<30)+((ll)(q[i].x+0.5)<<15)+((ll)(q[i].y+0.5)))%P;
}
void Inv(int *a,int *b,int len){
if(len==1)return b[0]=ksm(a[0],P-2),void();
Inv(a,b,len>>1);
static int c[N],d[N];
MTT(a,b,len,c),MTT(c,b,len,d);
fp(i,0,len-1)b[i]=dec(add(b[i],b[i]),d[i]);
}
struct node{
node *lc,*rc;vector<int>vec;int deg;
void Mod(const int *a,int *r,int n){
static int A[N],B[N],D[N];
int len=1;while(len<=n-deg)len<<=1;
fp(i,0,n)A[i]=a[n-i];fp(i,0,deg)B[i]=vec[deg-i];
fp(i,n-deg+1,len-1)B[i]=0;
Inv(B,D,len);
fp(i,n-deg+1,len-1)A[i]=D[i]=0;
MTT(A,D,len,A);
reverse(A,A+n-deg+1);
len=1;while(len<=max(n-deg,deg))len<<=1;
fp(i,0,deg)B[i]=vec[i];fp(i,deg+1,len-1)B[i]=0;
fp(i,n-deg+1,len-1)A[i]=0;
MTT(A,B,len,A);
fp(i,0,deg-1)r[i]=dec(a[i],A[i]);
}
void Mul(){
static int A[N],B[N];deg=lc->deg+rc->deg,vec.resize(deg+1);
int len=1;while(len<=max(lc->deg,rc->deg))len<<=1;
fp(i,0,lc->deg)A[i]=lc->vec[i];fp(i,lc->deg+1,len-1)A[i]=0;
fp(i,0,rc->deg)B[i]=rc->vec[i];fp(i,rc->deg+1,len-1)B[i]=0;
MTT(A,B,len,A);
fp(i,0,deg)vec[i]=A[i];
}
}pool[N<<1],*rt,*qwq,*pp=pool;
int A[N],a[N];
void solve(node* &p,int l,int r){
p=pp++;
if(l==r)return p->deg=1,p->vec.resize(2),p->vec[0]=a[l],p->vec[1]=1,void();
int mid=(l+r)>>1;
solve(p->lc,l,mid),solve(p->rc,mid+1,r);
p->Mul();
}
int b[25],res;
void calc(node *p,int l,int r,const int *A){
if(r-l<=512){
fp(i,l,r){
int x=a[i],c1,c2,c3,c4,now=A[r-l];
b[0]=1;fp(j,1,16)b[j]=mul(b[j-1],x);
for(R int j=r-l-1;j-15>=0;j-=16){
c1=(zero+1ll*now*b[16]+1ll*A[j]*b[15]+1ll*A[j-1]*b[14]+1ll*A[j-2]*b[13])%P,
c2=(zero+1ll*A[j-3]*b[12]+1ll*A[j-4]*b[11]+1ll*A[j-5]*b[10]+1ll*A[j-6]*b[9])%P,
c3=(zero+1ll*A[j-7]*b[8]+1ll*A[j-8]*b[7]+1ll*A[j-9]*b[6]+1ll*A[j-10]*b[5])%P,
c4=(zero+1ll*A[j-11]*b[4]+1ll*A[j-12]*b[3]+1ll*A[j-13]*b[2]+1ll*A[j-14]*b[1])%P,
now=(0ll+c1+c2+c3+c4+A[j-15])%P;
}
fd(j,(r-l)%16-1,0)now=(1ll*now*x+A[j])%P;
res=mul(res,now);
}
return;
}
int mid=(l+r)>>1,b[p->deg+1];
p->lc->Mod(A,b,p->deg-1),calc(p->lc,l,mid,b);
p->rc->Mod(A,b,p->deg-1),calc(p->rc,mid+1,r,b);
}
int n,s;
int main(){
// freopen("testdata.in","r",stdin);
scanf("%d%d",&n,&P),res=1,s=sqrt(n),Pre(),zero=0;
fp(i,1,s)a[i]=i-1;solve(qwq,1,s);
fp(i,1,s)a[i]=P-((i-1)*s+1);solve(rt,1,s);
fp(i,0,s)A[i]=qwq->vec[i];
rt->Mod(A,A,s);
fp(i,1,s)a[i]=(i-1)*s+1;
calc(rt,1,s,A);
fp(i,s*s+1,n)res=mul(res,i);
printf("%d\n",res);
return 0;
}
洛谷P5282 【模板】快速阶乘算法(多项式多点求值+MTT)的更多相关文章
- luogu P5667 拉格朗日插值2 拉格朗日插值 多项式多点求值 NTT
LINK:P5667 拉格朗日插值2 给出了n个连续的取值的自变量的点值 求 f(m+1),f(m+2),...f(m+n). 如果我们直接把f这个函数给插值出来就变成了了多项式多点求值 这个难度好像 ...
- 洛谷P5050 【模板】多项式多点求值
传送门 人傻常数大.jpg 因为求逆的时候没清零结果调了几个小时-- 前置芝士 多项式除法,多项式求逆 什么?你不会?左转你谷模板区,包教包会 题解 首先我们要知道一个结论\[f(x_0)\equiv ...
- 洛谷.4717.[模板]快速沃尔什变换(FWT)
题目链接 https://www.mina.moe/archives/7598 //285ms 3.53MB #include <cstdio> #include <cctype&g ...
- 【洛谷P5050】 【模板】多项式多点求值
code: #include <bits/stdc++.h> #define ll long long #define ull unsigned long long #define set ...
- luogu5282 【模板】快速阶乘算法
由于巨佬 shadowice1984 卡时限,本代码已经 T 请不要粘上去交 退役之后再写一个常数小的多项式取模吧 一句话题意:NP问题,求N!%P 吐槽:出题人太毒瘤...必须写任意模数NTT,而且 ...
- 多项式的各类计算(多项式的逆/开根/对数/exp/带余除法/多点求值)
预备知识:FFT/NTT 多项式的逆 给定一个多项式 F(x)F(x)F(x),请求出一个多项式 G(x)G(x)G(x),满足 F(x)∗G(x)≡1(mod xn)F(x)*G(x) \equiv ...
- P5282 【模板】快速阶乘算法(多项式运算+拉格朗日插值+倍增)
题面 传送门 前置芝士 优化后的\(MTT\)(四次\(FFT\)) 题解 这里有多点求值的做法然而被\(shadowice\)巨巨吊起来打了一顿,所以来学一下倍增 成功同时拿到本题最优解和最劣解-- ...
- 洛谷P3373 [模板]线段树 2(区间增减.乘 区间求和)
To 洛谷.3373 [模板]线段树2 题目描述 如题,已知一个数列,你需要进行下面两种操作: 1.将某区间每一个数加上x 2.将某区间每一个数乘上x 3.求出某区间每一个数的和 输入输出格式 输入格 ...
- 洛谷.3803.[模板]多项式乘法(FFT)
题目链接:洛谷.LOJ. FFT相关:快速傅里叶变换(FFT)详解.FFT总结.从多项式乘法到快速傅里叶变换. 5.4 又看了一遍,这个也不错. 2019.3.7 叕看了一遍,推荐这个. #inclu ...
随机推荐
- python's import mechanism
[python's import mechanism] 问题描述: [A.py] from B import D class C:pass [B.py] from A import C class D ...
- 再谈C#编码规范
编码规范是老生常谈的问题,现在再看代码规范可能不会再去在意变量,控件的命名方法等,而是更加关注代码的实用性. 首先我们要明白一下几点, 1.代码写出来除了让他跑起来还有个非常非常重要的作用是维护,因为 ...
- 02-SSH综合案例:需求分析(后台)
1.1.7 用户模块:(后台) 不用添加了,添加的话在前台就注册了. 查询所有用户: 修改用户信息: 删除用户信息: 1.1.8 一级分类:(后台) 主要都还是增删改查的操作 查询所有一级分类: ...
- 二叉树垂直遍历 · Binary Tree Vertical Order Traversal
[抄题]: 给定二叉树,返回其节点值的垂直遍历顺序. (即逐列从上到下).如果两个节点在同一行和同一列中,则顺序应 从左到右. 给定一个二叉树 {3,9,20,#,#,15,7} 3 /\ / \ 9 ...
- __next__和__iter__实现迭代器协议
---恢复内容开始--- #_*_coding:utf-8_*_ __author__ = 'Linhaifeng' class Foo: def __init__(self,x): self.x=x ...
- 四元数--结合《real time rendering》中关于四元数部分
四元数产生于1843年,是复数的一个扩展,所以里面包含了一些复数的运算.直到1985年才在图形学中使用. 四元数的优势是,相对与矩阵和欧拉角,四元数更直观和方便.四元数还可以用作某些方向上的插值,而欧 ...
- git忽略某个文件
data/config/config.ini.php
- Atom 编辑器侧边栏忽略隐藏文件
设置中配置需要忽略的文件后缀 package中找到treeview,勾选上这个配置就行
- Introduction to Razor Pages in ASP.NET Core
https://docs.microsoft.com/en-us/aspnet/core/mvc/razor-pages/ 从ASP.NET Core 2.0.0版本之后,添加了新的特性Razor p ...
- IntelliJ IDEA 2017版开发SpringBoot之fastJsonHttpMessageConvert使用
继承WebMvcConfigurerAdapter,改写成自己的json转换工具的写法 1.建立实体类 package com.fastjson; import com.alibaba.fastjso ...