题解 P4512 【【模板】多项式除法】
前言
原理有大佬写了
所以蒟蒻只讲下本题的代码细节
我看懂的大佬博客:博客地址
因为可能知道了大致的步骤还有很多细的地方不理解
导致写的时候要花很久
并且看到大佬们好像都是用递归写的
希望能有帮助吧
背景
由于我太菜了实在看不懂其他大佬的代码只能自己写
于是因为很多的细节原因和并一些大佬的奇异写法误导调了N+个小时
# 详细的地方还是看代码里面说明吧
因为没怎么优化常数比较大吧
有写代码是可以简化的
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define C getchar()-48
inline ll read()
{
ll s=,r=;
char c=C;
for(;c<||c>;c=C) if(c==-) r=-;
for(;c>=&&c<=;c=C) s=(s<<)+(s<<)+c;
return s*r;
}
const ll p=,G=,N=;
ll n,m;
ll f[N],g[N],q[N],r[N],inv[N],rev[N],c[N];
ll tmp1[N],tmp2[N];
inline ll ksm(ll a,ll b)//..快速幂
{
ll ans=;
while(b)
{
if(b&) ans=(ans*a)%p;
a=(a*a)%p;
b>>=;
}
return ans;
}
inline void ntt(ll *a,ll n,ll kd)//ntt日常操作
{
for(int i=;i<n;i++)
if(i<rev[i])
swap(a[i],a[rev[i]]);
for(int i=;i<n;i<<=)
{
ll gn=ksm(G,(p-)/(i<<));
for(int j=;j<n;j+=(i<<))
{
ll t1,t2,g=;
for(int k=;k<i;k++,g=g*gn%p)
{
t1=a[j+k],t2=g*a[j+k+i]%p;
a[j+k]=(t1+t2)%p,a[j+k+i]=(t1-t2+p)%p;
}
}
}
if(kd==) return;
ll ny=ksm(n,p-);
reverse(a+,a+n);
for(int i=;i<n;i++) a[i]=a[i]*ny%p;
}
inline void cl(ll *a,ll *b,ll n,ll m,ll len,ll w)//处理
{
for(int i=;i<len;i++) tmp1[i]=i<n?a[i]:;//复制 清空多余//因为tmp被使用多遍 而在做ntt时 用的是长度为len的
for(int i=;i<len;i++) tmp2[i]=i<m?b[i]:;//而有效的值只有它的得出的长度 后面其它的在模意义下都被清掉了 但之前在写的时候有的地方并没有清
//为了避免出错所以一定要清空 (在这个代码里)//..不要打成 i<n?tmp1[i]=a[i]:0;...只有像我这种蒟蒻才会犯这种错误吧
for(int i=;i<len;i++) rev[i]=(rev[i>>]>>)|((i&)<<(w-));//蝴蝶
}
inline void polyinv(ll *a,ll *b,ll ed)//递推版
{
b[]=ksm(a[],p-);//设初始值 a*b=1(mod=x)b的值
for(int k=,j=;k<=(ed<<);k<<=,j++)//从两个长度为k的多项式a,b递推
{//!!因为这份代码的递推算的是 两个长度为a的多项式在模(m^k)次下的逆元
//所以如果直接用ed为条件只会推出小于ed的逆元 所以ed要再乘一倍
//所以多项式总共需要的范围要为4倍所以N要4倍
ll len=k<<; //len 两式子计算后大小
cl(a,b,k,k,len,j+);//处理//j+1 要看len调整 因为len乘上了一倍 所以j在处理时也要加上1 之前没有加被坑了好久
ntt(tmp1,len,);ntt(tmp2,len,);//注意不要直接用a,b算 因为ntt后原多项式的值会变 为了方便所以先复制一遍在用复制的多项式算
for(int i=;i<len;i++) b[i]=tmp2[i]*(2ll-tmp1[i]*tmp2[i]%p+p)%p;//求逆
ntt(b,len,-);
for(int i=k;i<len;i++) b[i]=;//清空会被模的 //!!!不能删 因为下次递推是直接把0--len都作为有用的做下次运算了
}
}
inline void polymul(ll *a,ll *b,ll *c,ll n,ll m)//计算多项式相乘
{
ll len=,w=;
while(len<=(n+m)) len<<=,w++;
cl(a,b,n,m,len,w);//这里的次数(w)不用加1因为两者都是同不改变的
ntt(tmp1,len,);ntt(tmp2,len,);
for(int i=;i<len;i++) c[i]=tmp1[i]*tmp2[i]%p;
ntt(c,len,-);
}
inline void work() //f=q*g+r ask q,r f,g下标从0--n,0--m
{ reverse(f,f++n);//对应各式的反转操作
reverse(g,g++m); polyinv(g,inv,n-m+);//求逆 因为反转后使r能够被忽略所以是在模x^(n-m+1)意义下的, 所以只要算出g在模x^(n-m+1)下的逆元
polymul(f,inv,q,n+,n-m+);//计算q reverse(q,q+n-m+);//将原式反转回来
reverse(f,f+n+);
reverse(g,g+m+); polymul(g,q,r,m+,n-m+);//计算q*g的值
for(int i=;i<m;i++) r[i]=(f[i]-r[i]+p)%p;//相减算出r
}
int main()//注意输入的多项式是 0--n 和0--m 不是长度为n,m;
{
n=read(),m=read(); //读入
for(int i=;i<=n;i++) f[i]=read();
for(int i=;i<=m;i++) g[i]=read();
work();
for(int i=;i<=n-m;i++) printf("%lld ",q[i]);printf("\n");//输出
for(int i=;i<m;i++) printf("%lld ",r[i]);
return ;
}
# 干净的代码
#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define C getchar()-48
inline ll read()
{
ll s=,r=;
char c=C;
for(;c<||c>;c=C) if(c==-) r=-;
for(;c>=&&c<=;c=C) s=(s<<)+(s<<)+c;
return s*r;
}
const ll p=,G=,N=;
ll n,m;
ll f[N],g[N],q[N],r[N],inv[N],rev[N],c[N];
ll tmp1[N],tmp2[N];
inline ll ksm(ll a,ll b)
{
ll ans=;
while(b)
{
if(b&) ans=(ans*a)%p;
a=(a*a)%p;
b>>=;
}
return ans;
}
inline void ntt(ll *a,ll n,ll kd)
{
for(int i=;i<n;i++)
if(i<rev[i])
swap(a[i],a[rev[i]]);
for(int i=;i<n;i<<=)
{
ll gn=ksm(G,(p-)/(i<<));
for(int j=;j<n;j+=(i<<))
{
ll t1,t2,g=;
for(int k=;k<i;k++,g=g*gn%p)
{
t1=a[j+k],t2=g*a[j+k+i]%p;
a[j+k]=(t1+t2)%p,a[j+k+i]=(t1-t2+p)%p;
}
}
}
if(kd==) return;
ll ny=ksm(n,p-);
reverse(a+,a+n);
for(int i=;i<n;i++) a[i]=a[i]*ny%p;
}
inline void cl(ll *a,ll *b,ll n,ll m,ll len,ll w)
{
for(int i=;i<len;i++) tmp1[i]=i<n?a[i]:;
for(int i=;i<len;i++) tmp2[i]=i<m?b[i]:;
for(int i=;i<len;i++) rev[i]=(rev[i>>]>>)|((i&)<<(w-));
}
inline void polyinv(ll *a,ll *b,ll ed)
{
b[]=ksm(a[],p-);
for(int k=,j=;k<=(ed<<);k<<=,j++)
{
ll len=k<<;
cl(a,b,k,k,len,j+);
ntt(tmp1,len,);ntt(tmp2,len,);
for(int i=;i<len;i++) b[i]=tmp2[i]*(2ll-tmp1[i]*tmp2[i]%p+p)%p;
ntt(b,len,-);
for(int i=k;i<len;i++) b[i]=;
}
}
inline void polymul(ll *a,ll *b,ll *c,ll n,ll m)
{
ll len=,w=;
while(len<=(n+m)) len<<=,w++;
cl(a,b,n,m,len,w);
ntt(tmp1,len,);ntt(tmp2,len,);
for(int i=;i<len;i++) c[i]=tmp1[i]*tmp2[i]%p;
ntt(c,len,-);
}
inline void work()
{ reverse(f,f++n);
reverse(g,g++m); polyinv(g,inv,n-m+);
polymul(f,inv,q,n+,n-m+); reverse(q,q+n-m+);
reverse(f,f+n+);
reverse(g,g+m+); polymul(g,q,r,m+,n-m+);
for(int i=;i<m;i++) r[i]=(f[i]-r[i]+p)%p;
}
int main()
{
n=read(),m=read();
for(int i=;i<=n;i++) f[i]=read();
for(int i=;i<=m;i++) g[i]=read();
work();
for(int i=;i<=n-m;i++) printf("%lld ",q[i]);printf("\n");
for(int i=;i<m;i++) printf("%lld ",r[i]);
return ;
}
代码
题解 P4512 【【模板】多项式除法】的更多相关文章
- 洛谷 P4512 [模板] 多项式除法
题目:https://www.luogu.org/problemnew/show/P4512 看博客:https://www.cnblogs.com/owenyu/p/6724611.html htt ...
- 洛谷.4512.[模板]多项式除法(NTT)
题目链接 多项式除法 & 取模 很神奇,记录一下. 只是主要部分,更详细的和其它内容看这吧. 给定一个\(n\)次多项式\(A(x)\)和\(m\)次多项式\(D(x)\),求\(deg(Q) ...
- [洛谷P4512]【模板】多项式除法
题目大意:给定一个$n$次多项式$F(x)$和一个$m$次多项式$G(x)$,请求出多项式$Q(x),R(x)$,满足: 1. $Q(x)$次数为$n-m$,$R(x)$次数小于$m$2. $F(x) ...
- P4512 【模板】多项式除法
思路 多项式除法板子 多项式除法 给出\(A(x)\)和\(B(x)\),求一个\(n-m\)次的多项式\(D(x)\),一个\(m-1\)次多项式\(R(x)\),满足 \[ A(x)=B(x)D( ...
- 【Codechef】Random Number Generator(多项式除法)
题解 前置技能 1.多项式求逆 求\(f(x)\*g(x) \equiv 1 \pmod {x^{t}}\) 我们在t == 1时,有\(f[0] = frac{1}{g[0]}\) 之后呢,我们倍增 ...
- Re.多项式除法/取模
前言 emmm又是暂无 前置 多项式求逆 多项式除法/取模目的 还是跟之前一样顾名思义] 给定一个多项式F(x),请求出多项式Q(x)和R(x),满足F(x)=Q(x)∗G(x)+R(x),R项数小于 ...
- xdoj-1211 (尧老师要教孩子解方程) :多项式除法
想法: 1 由于所有a[i] 是不为0的整数 所以解x是整数 2 其次解是an的约数 3 分解a[n] 用多项式除法判断约数是否为整式的解 #include<cstdio> #includ ...
- luogu P4512 多项式除法 (模板题、FFT、多项式求逆)
手动博客搬家: 本文发表于20181206 14:42:53, 原地址https://blog.csdn.net/suncongbo/article/details/84853342 题目链接: ht ...
- 2019.01.02 洛谷P4512 【模板】多项式除法
传送门 解析 代码: #include<bits/stdc++.h> #define ri register int using namespace std; typedef long l ...
随机推荐
- MySQL 优化集锦
case 1: 如果筛选or条件有多个的时候,应该将最好判断的放在最前面,将最不好判断的放在最后面 比如,有一个学生表,想要找出其中年龄是20岁,住址中包含666这个数字的记录.可以下面这两个方案: ...
- C调用C++, C++调用C方法
1. C 调用 C++封装好后的函数: -> 在C++中有一个函数 int main_cpp(): -> 首先构建头文件, #ifndef CPP_FILE_H #define CPP ...
- JavaScript中变量、执行环境、作用域与C#中的异同
首先需要明确一个执行环境的概念,执行环境这个概念是用来理解作用域的,在js中,执行环境分为全局执行环境和局部(function)执行环境,而在C#这类的C类语言中,还有一个块级别的执行环境,如if语句 ...
- java.util(Date和Calendar)
public class Date implements java.io.Serializable, Cloneable, Comparable<Date> { public Date() ...
- IDEA将项目上传至码云/GitHub托管
怎么将本地的项目放到码云或者GitHub去托管了?(以码云为例) 一.创建远程项目 第一步:点击创建项目 第二步:填写项目相关信息 第三步:复制远程的项目地址,注意:此处码云官方已经给出上传项目方法, ...
- Go To Oracle
1.下载mingw (gcc 编译)---win32 2.下载OCI最新版,存放于C:\instantclient_12_1 ---win32 3.下载OCI SDK最新版,存放于C:\ins ...
- [转帖]TLS 1.3 VS TLS 1.2,让你明白 TLS 1.3 的强大
TLS 1.3 VS TLS 1.2,让你明白 TLS 1.3 的强大 https://www.jianshu.com/p/efe44d4a7501?utm_source=oschina-app 又拍 ...
- Kafka-Flume-elasticsearch
a1.sources = kafkaSource a1.channels = memoryChannel a1.sinks = elasticsearch a1.sources.kafkaSource ...
- python爬虫scrapy的LinkExtractor
使用背景: 我们通常在爬去某个网站的时候都是爬去每个标签下的某些内容,往往一个网站的主页后面会包含很多物品或者信息的详细的内容,我们只提取某个大标签下的某些内容的话,会显的效率较低,大部分网站的都是按 ...
- python爬虫scrapy之rules的基本使用
Link Extractors Link Extractors 是那些目的仅仅是从网页(scrapy.http.Response 对象)中抽取最终将会被follow链接的对象。 Scrapy默认提供2 ...