多项式题
P4841 [集训队作业2013]城市规划
\[设G(n)表示n个点的有标号无向图数量,我们知道,G(n)=2^{\binom{n}{2}}\\
设F(n)表示n个点的有标号无向联通图数量,显然\\
\text{我们枚举一号店所在的联通块大小,剩下部分是任意图,合起来就是n个点的有标号无向图个数,然后暴力拆二项式系数}\\
\begin{aligned}
G(n)&=\sum_{i=1}^n{\binom{n-1}{i-1}F(i)G(n-i)}\\
2^{\binom{n}{2}}&=\sum_{i=1}^n{\frac{(n-1)!}{(n-i)!(i-1)!}F(i)2^{\binom{n-i}{2}}}\\
\frac{2^{\binom{n}{2}}}{(n-1)!} &=\sum_{i=1}^n{\frac{2^{\binom{n-i}{2}}}{(n-i)!}\frac{F(i)}{(i-1)!}}\\
\end{aligned}
\\
设A(n)=\frac{2^{\binom{n}{2}}}{(n-1)!}\\
设B(n)=\frac{2^{\binom{n}{2}}}{n!}\\
设C(n)=\frac{F(n)}{(n-1)!}\\
A=B*C\\
C=A*B^{-1}\\
我们做一遍多项式求逆,再乘上(n-1)!就可以求出f
\]
代码
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const LL mod = 1004535809, G = 3, Gi = 334845270;
const int maxn = 8e5 + 5;
LL fsp(LL a, LL b = mod - 2)
{
LL s = 1;
while (b)
{
if (b & 1)
s = s * a % mod;
b >>= 1;
a = a * a % mod;
}
return s;
}
int r[maxn];
void NTT(LL *a, int limit, int type)
{
for (int i = 0; i < limit; i++)
if (i < r[i])
swap(a[i], a[r[i]]);
for (int mid = 1; mid < limit; mid <<= 1)
{
LL Wn = fsp(type == 1 ? G : Gi, (mod - 1) / (mid << 1));
for (int j = 0; j < limit; j += (mid << 1))
{
LL w = 1;
for (int k = 0; k < mid; k++, w = Wn * w % mod)
{
LL x = a[j + k], y = w * a[j + k + mid] % mod;
a[j + k] = (x + y) % mod;
a[j + k + mid] = (x - y + mod) % mod;
}
}
}
}
LL a[maxn], x[maxn], y[maxn];
LL b[2][maxn];
void mul(LL *a, LL *b, LL *ans, int n, int m)
{
memset(x, 0, sizeof(x));
memset(y, 0, sizeof(y));
for (int i = 0; i <= n; i++)
x[i] = a[i];
for (int i = 0; i <= m; i++)
y[i] = b[i];
LL limit = 1, L = 0;
while (limit <= n + m)
limit <<= 1, L++;
for (int i = 0; i < limit; i++)
r[i] = (r[i >> 1] >> 1) | ((i & 1) << (L - 1));
NTT(x, limit, 1), NTT(y, limit, 1);
for (int i = 0; i < limit; i++)
ans[i] = x[i] * y[i] % mod;
NTT(ans, limit, -1);
LL inv = fsp(limit);
for (int i = 0; i < limit; i++)
ans[i] = ans[i] * inv % mod;
}
void invv(LL *a, LL *ans,int n)
{
int bas = 1;
int cur = 0;
b[cur][0] = fsp(a[0]);
while (bas <= (n << 1))
{
cur ^= 1;
memset(b[cur], 0, sizeof(b[cur]));
for (int i = 0; i < bas; i++)
{
b[cur][i] = (b[cur^ 1][i ] << 1) % mod;
}
mul(b[cur ^ 1], b[cur ^ 1], b[cur ^ 1], bas, bas);
mul(b[cur ^ 1], a, b[cur ^ 1], bas, bas);
for (int i = 0; i < bas; ++i)
b[cur][i] = (b[cur][i] - b[cur ^ 1][i]+mod) % mod;
bas <<= 1;
}
for(int i=0;i<=n;i++)ans[i]=b[cur][i];
}
LL fac[maxn],inv[maxn];
LL A[maxn],B[maxn],D[maxn];
LL C(int n,int m){
if(m>n)return 0;
return fac[n]*inv[m]%mod*inv[n-m]%mod;
}
int main()
{
fac[0]=inv[0]=1;
for(int i=1;i<=200000;i++){
fac[i]=fac[i-1]*i%mod;
inv[i]=fsp(fac[i]);
}
int n;
cin >> n;
D[0]=1;
for (int i = 1; i <= n; i++)
{
A[i]=fsp(2,(1ll*i*(i-1)/2)%(mod-1))*inv[i-1]%mod;
D[i]=fsp(2,(1ll*i*(i-1)/2)%(mod-1))*inv[i]%mod;
}
invv(D,D,n);
for(int i=n+1;i<=maxn-100;i++)D[i]=0;
mul(A,D,B,n,n);
cout<<B[n]*fac[n-1]%mod;
return 0;
}
CF438E The Child and Binary Tree
科技没学到家,先咕了
P4451 [国家集训队]整数的lqp拆分
\[我们设答案为G(n),斐波那契数列为F,有\\
G(n)=\sum_{i=1}^nG(i)F(n-i)\\
我们令G(0)=1,那么\\
G(n)=\sum_{i=1}^nG(i)F(n-i) + [n=1]\\
G=G*F+1\\
我们考虑求出G的生成函数,那么就要从F的生成函数出发。\\
\begin{aligned}
F(x)&=\sum_{i=0}^{\infty}{f_ix^i}
=\sum_{i=2}^{\infty}{f_ix^i} + x\\
xF(x)&=\sum_{i=0}^{\infty}{f_ix^{i+1}}
=\sum_{i=1}^{\infty}{f_{i-1}x^i}
=\sum_{i=2}^{\infty}{f_{i-1}x^i}\\
x^2F(x)&=\sum_{i=0}^{\infty}{f_ix^{i+2}}
=\sum_{i=2}^{\infty}{f_{i-2}x^i}\\
xF(x)+x^2F(x)&=\sum_{i=2}^{\infty}{f_{i-2}x^i+f_{i-1}x^i}
=\sum_{i=2}^{\infty}{f_ix^i}
=F(x)-x\\
\end{aligned}
\\
F(x)=\frac{x}{1-x-x^2}\\
\begin{aligned}
G&=\frac{1}{1-F}\\
G(x)&=\frac{1}{1-\frac{x}{1-x-x^2}}\\
&=\frac{1}{\frac{1-2x-x^2}{1-x-x^2}}\\
&=\frac{1-x-x^2}{1-2x-x^2}\\
&=1-\frac{x}{x^2+2x-1}\\
\end{aligned}
\\
设x_1,x_2分别为{x^2+2x-1}两根\\
\begin{aligned}
-\frac{x}{x^2+2x-1}&=-\frac{x}{(x-x_1)(x-x_2)}\\
&=\frac{((x-x_1)-(x-x_2))x}{(x-x_1)(x-x_2)(x_1-x_2)}\\
&=\frac{(x-x_2)-(x-x_1)}{(x-x_1)(x-x_2)}\frac{x}{x_2-x_1}\\
&=(\frac{1}{x-x_1}-\frac{1}{x-x_2})\frac{x}{x_2-x_1}\\
&=(\frac{1}{x_1-x}-\frac{1}{x_2-x})\frac{x}{x_1-x_2}\\
&=(\frac{1}{x_1}\frac{1}{1-\frac{x}{x_1}}-\frac{1}{x_2}\frac{1}{1-\frac{x}{x_2}})\frac{x}{x_1-x_2}\\
&=(\frac{1}{x_1}{\sum_{i=0}^{\infty}{(\frac{x}{x_1})^i}}-\frac{1}{x_2}{\sum_{i=0}^{\infty}{(\frac{x}{x_2})^i}})\frac{x}{x_1-x_2}\\
&=({\sum_{i=0}^{\infty}{(\frac{x}{x_1})^{i+1}}}-{\sum_{i=0}^{\infty}{(\frac{x}{x_2})^{i+1}}})\frac{1}{x_1-x_2}\\
\end{aligned}
\\
\;[x^n]G(n)=(\frac{1}{x_1})^n-(\frac{1}{x_2})^n)\frac{1}{x_1-x_2}\\
我们知道x_1=1+\sqrt{2},x_2=1-\sqrt{2}\\
因此G(n)=\frac{\sqrt{2}}{4}((1+\sqrt{2})^n-(1-\sqrt{2})^n)\\
\sqrt{2} \equiv 59713600 \pmod(1000000007)\\
因此使用高精取模 + 普通快速幂就可AC本题
\]
代码
#include<bits/stdc++.h>
using namespace std;
#define LL long long
const LL P = 1e9+7;
const LL Pi=P-1;
const LL sq2=59713600;
const LL inv4=250000002;
LL fsp(LL a,LL b)
{
LL s=1;
while(b)
{
if(b&1)s=s*a%P;
b>>=1;
a=a*a%P;
}
return s;
}
int main()
{
string a;
cin>>a;
LL mc=0;
for(int i=0;i<a.length();i++)
{
int x=a[i]-'0';
mc=(mc*10%Pi + x)%Pi;
}
LL y=sq2*inv4%P;
LL x1=sq2+1;
LL x2=(1-sq2+P)%P;
cout<<y*(fsp(x1,mc) - fsp(x2,mc)+P)%P;
return 0;
}
P4491 [HAOI2018]染色
\[我们设F(k)为钦定至少有k种颜色恰好S次的方案数\\
G(k)为恰好有k种颜色恰好S次的方案数\\
显然F(k)=\binom{m}{k}\frac{(kS)!}{(S!)^k}(n-kS)^{m-k}\\
F(k)=\sum_{i=k}^n\binom{i}{k}G(i)\\
\begin{aligned}
G(k)&=\sum_{i=k}^n(-1)^{i-k}\binom{i}{k}F(i)\\
&=\sum_{i=k}^n{(-1)^{i-k}\frac{i!}{(i-k)!k!}F(i)}\\
G(k)k!&=\sum_{i=k}^n{\frac{(-1)^{i-k}}{(i-k)!}i!F(i)}
\end{aligned}
\]
直接爆上NTT即可
代码
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int maxn = 4e5+10,P=1004535809,G=3,Gi=334845270;
int n,m,limit=1,L,r[maxn];
LL fsp(LL a,LL k){
LL s=1;
while(k){
if(k&1)s*=a,s%=P;
a=a*a%P;
k>>=1;
}
return s;
}
void NTT(LL *a,int type){
for(int i=0;i<limit;i++)if(i<r[i])swap(a[i],a[r[i]]);
for(int mid=1;mid<limit;mid<<=1){
LL Wn= fsp( type == 1 ? G : Gi , (P - 1) / (mid << 1));
for(int j=0;j<limit;j+=(mid<<1)){
LL w=1;
for(int k=0;k<mid;k++,w=Wn*w%P)
{
LL x=a[j+k],y=w*a[j+k+mid]%P;
a[j+k]=(x+y)%P;
a[j+k+mid]=(x-y+P)%P;
}
}
}
}
LL a[maxn],b[maxn];
void mul(LL *a,LL *b,LL *ans,int n,int m){
limit=1,L=0;
while(limit<=n+m)limit<<=1,L++;
for(int i=0;i<limit;i++)r[i]=(r[i>>1]>>1)|((i&1)<<(L-1));
NTT(a,1),NTT(b,1);
for(int i=0;i<limit;i++)ans[i]=a[i]*b[i]%P;
NTT(ans,-1);
LL inv = fsp(limit, P - 2);
for(int i=0;i<=n+m;i++)
{
ans[i]=ans[i]*inv%P;
}
}
LL fac[12000005],inv[12000005];
LL A[maxn],B[maxn],f[maxn],w[maxn],h[maxn];
int x,S;
LL C(int m,int n){
return fac[m]*inv[n]%P*inv[m-n]%P;
}
int main()
{
cin>>n>>m>>S;
for(int i=0;i<=m;i++)
scanf("%lld",&w[i]);
x=min(m,n/S);
fac[0]=1;
inv[0]=1;
for(int i=1;i<=max(n,m);i++){
fac[i]=1ll*fac[i-1]*i%P;
}
inv[max(n,m)]=fsp(fac[max(n,m)],P-2);
for(int i=max(n,m)-1;i>=1;i--){
inv[i]=inv[i+1]*(i+1)%P;
}
for(int i=0;i<=x;i++){
f[i]=C(m,i)*C(n,i*S)%P*fac[i*S]%P*fsp(inv[S],i)%P*fsp(m-i,n-i*S)%P;
B[x-i]=f[i]*fac[i]%P;
if(i%2==0)A[i]=inv[i];
else A[i]=P-inv[i];
}
mul(A,B,h,x,x);
LL ans=0;
for(int i=0;i<=x;i++){
ans+=h[x-i]*w[i]%P*inv[i]%P;
ans%=P;
}
cout<<ans;
return 0;
}
P4389 付公主的背包
不会多项式EXP,咕咕咕
P5900 无标号无根树计数
不会置换,咕咕咕
遗忘的集合:
会做法,不会MTT,咕咕咕
P5488 差分与前缀和
\[\begin{aligned}
对于一个多项式:\\
F(x)&=\sum_{i=0}^{\infty}{f_ix^i}\\
G(x)&=\sum_{i=0}^{\infty}{(f_{i}-f_{i-1})x^i }\\
&=\sum_{i=0}^{\infty}{f_{i}x^i} - \sum_{i=0}^{\infty}{f_{i-1}x^i}\\
&=\sum_{i=0}^{\infty}{f_{i}x^i} - \sum_{i=0}^{\infty}{f_ix^{i+1}}\\
&=\sum_{i=0}^{\infty}{f_{i}x^i} - x\sum_{i=0}^{\infty}{f_ix^i}\\
G(x)&=F(x)-xF(x)\\
&=F(x)(1-x)\\
多项式乘法具有结合律,&因此F(x)的k阶差分为F*(1-x)^k\\
H(x)&=\sum_{i=0}^{\infty}{(\sum_{j=0}^i}f_j)x^i\\
&=\sum_{i=0}^{\infty}{(\sum_{j=0}^i}f_jx^jx^{i-j})\\
&=\sum_{i=0}^{\infty}{x^i(\sum_{j=0}^{\infty}}f_jx^j)\\
&=F(x)\sum_{i=0}^{\infty}{x^i}\\
&=F(x)\sum_{i=0}^{\infty}{\frac{1}{1-x}}\\
F(x)的k阶前缀和为F*({\frac{1}{1-x}})^k
&我们把(1-x)^k 和 ({\frac{1}{1-x}})^展开,发现它们都含有\binom{k}{x}的项,虽然k很大,但是\\
&\binom{k \bmod p}{x} \equiv \binom{k}{x} \pmod(p),因为下降幂底数可取模。\\
&我们递推求组合数,即可AC
\end{aligned}
\]
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5+5e4;
const int P=1004535809,g=3,gi=334845270;
int lim=1,r[maxn],c[maxn],w[maxn];
void joke()
{
}
int fsp(int a,int b=P-2)
{
int s=1;
while(b)
{
if(b&1)s=1ll*s*a%P;
b>>=1;
a=1ll*a*a%P;
}
return s;
}
void init(int len)
{
int l=0;
lim=1;
while(lim<=len)lim<<=1,l++;
int wn=fsp(g,(P-1)/lim),cw=fsp(gi,(P-1)/lim);
w[0]=c[0]=1;
for(int i=1;i<lim;i++)
{
r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
w[i]=1ll*w[i-1]*wn%P;
c[i]=1ll*c[i-1]*cw%P;
}
}
void NTT(int num[],int typ)
{
for(int i=0;i<lim;i++)if(i<r[i])swap(num[i],num[r[i]]);
if(typ==1)
{
for(int m=1,t=(lim>>1);m<lim;m<<=1,t>>=1)
{
for(int i=0;i<lim;i+=(m<<1))
{
for(int j=0;j<m;j++)
{
int x=num[i+j],y=1ll*num[i+j+m]*w[t*j]%P;
num[i+j]=(x+y)%P;
num[i+j+m]=(x-y+P)%P;
}
}
}
}else{
for(int m=1,t=(lim>>1);m<lim;m<<=1,t>>=1)
{
for(int i=0;i<lim;i+=(m<<1))
{
for(int j=0;j<m;j++)
{
int x=num[i+j],y=1ll*num[i+j+m]*c[t*j]%P;
num[i+j]=(x+y)%P;
num[i+j+m]=(x-y+P)%P;
}
}
}
int invlen=fsp(lim);
for(int i=0;i<lim;i++)
{
num[i]=1ll*num[i]*invlen%P;
}
}
}
void poly_mul(int a[],int b[],int len)
{
init(len);
NTT(a,1),NTT(b,1);
for(int i=0;i<lim;i++)a[i]=1ll*a[i]*b[i]%P;
NTT(a,-1);
}
void poly_inv(int a[],int b[],int len)
{
int tmp[maxn]={};
b[0]=fsp(a[0]);
int op=1,ln=1;
while(ln<(len<<1))
{
init(ln);
for(int i=0;i<ln;i++)tmp[i]=a[i];
NTT(tmp,1),NTT(b,1);
for(int i=0;i<lim;i++)b[i]=1ll*(1ll*2*b[i]-1ll*b[i]*b[i]%P*tmp[i]%P+P)%P;
NTT(b,-1);
for(int i=ln;i<lim;i++)b[i]=0;
ln<<=1;
}
}
void poly_sqrt(int a[],int b[],int len)
{
int tmp[maxn]={},H[maxn]={},tmp2[maxn]={};
b[0]=1;
int ln=1;
while(ln<(len<<1))
{
for(int i=0;i<ln;i++)tmp[i]=a[i];
for(int i=0;i<ln;i++)tmp2[i]=2ll*b[i]%P;
poly_inv(tmp2,H,ln);
init(ln);
NTT(b,1),NTT(tmp,1),NTT(H,1);
for(int i=0;i<lim;i++)b[i]=1ll*H[i]%P*(tmp[i]+1ll*b[i]*b[i]%P)%P;
NTT(b,-1);
for(int i=ln;i<lim;i++)b[i]=0;
for(int i=0;i<lim;i++)H[i]=tmp[i]=0;
ln<<=1;
}
}
void poly_deri(int num[],int len)
{
for(int i=0;i<len-1;i++)
{
num[i]=1ll*(i+1)*num[i+1]%P;
}
num[len-1]=0;
}
void poly_intg(int num[],int len)
{
for(int i=len;i>0;i--)
{
num[i]=1ll*num[i-1]*fsp(i)%P;
}
num[0]=0;
}
void poly_Lyin(int a[],int b[],int len)
{
int tmp[maxn]={};
for(int i=0;i<len;i++)tmp[i]=a[i];
poly_inv(tmp,b,len);
poly_deri(tmp,len);
poly_mul(b,tmp,2*len-1);
poly_intg(b,len-1);
}
int a[maxn],b[maxn],n,k,t;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n;
string s;
cin>>s;
for(int i=0;i<s.length();i++)
{
int x=s[i]-'0';
k=10ll*k%P+x;
}
cin>>t;
for(int i=0;i<n;i++)
{
cin>>a[i];
}
if(t&1)
{
b[0]=1;
for(int i=1;i<n;i++)
{
b[i]=(P-1ll*b[i-1]*(k-i+1)%P*fsp(i)%P)%P;
}
}else
{
b[0]=1;
for(int i=1;i<n;i++)
{
b[i]=1ll*b[i-1]*(k+i-1)%P*fsp(i)%P;
}
}
poly_mul(a,b,2*n);
for(int i=0;i<n;i++)
{
cout<<a[i]<<" ";
}
return 0;
}
P5641 【CSGRound2】开拓者的卓识
\[我们发现,a_i对答案造成贡献的一组方案,一定满足\\
l_k \le l_{k-1} \le \dotsc \le l_2 \le i \le r_2 \le \dotsc\le r_{k-1} \le r_k \\
发现它可以转化为我们熟识的模型:\\
l_k -k+1\lt l_{k-1} -k+2 \lt \dotsc \lt l_2+1 \lt i\\
i \lt r_2 +1 \lt \dotsc\lt r_{k-1} +k-2\lt r_k +k-1 \lt r+k-1\\
f(r)=\sum_{i=0}^{r-1} a_{i+1}\binom{i+k-1}{k-1}\binom{r-i-1+k-1}{k-1}\\
发现这是一个卷积式,我们大力卷积
\]
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5+5e4;
const int P=998244353,g=3,gi=332748118;
int lim=1,r[maxn],c[maxn],w[maxn];
int fsp(int a,int b=P-2)
{
int s=1;
while(b)
{
if(b&1)s=1ll*s*a%P;
b>>=1;
a=1ll*a*a%P;
}
return s;
}
void init(int len)
{
int l=0;
lim=1;
while(lim<=len)lim<<=1,l++;
int wn=fsp(g,(P-1)/lim),cw=fsp(gi,(P-1)/lim);
w[0]=c[0]=1;
for(int i=1;i<lim;i++)
{
r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
w[i]=1ll*w[i-1]*wn%P;
c[i]=1ll*c[i-1]*cw%P;
}
}
void NTT(int num[],int typ)
{
for(int i=0;i<lim;i++)if(i<r[i])swap(num[i],num[r[i]]);
if(typ==1)
{
for(int m=1,t=(lim>>1);m<lim;m<<=1,t>>=1)
{
for(int i=0;i<lim;i+=(m<<1))
{
for(int j=0;j<m;j++)
{
int x=num[i+j],y=1ll*num[i+j+m]*w[t*j]%P;
num[i+j]=(x+y)%P;
num[i+j+m]=(x-y+P)%P;
}
}
}
}else{
for(int m=1,t=(lim>>1);m<lim;m<<=1,t>>=1)
{
for(int i=0;i<lim;i+=(m<<1))
{
for(int j=0;j<m;j++)
{
int x=num[i+j],y=1ll*num[i+j+m]*c[t*j]%P;
num[i+j]=(x+y)%P;
num[i+j+m]=(x-y+P)%P;
}
}
}
int invlen=fsp(lim);
for(int i=0;i<lim;i++)
{
num[i]=1ll*num[i]*invlen%P;
}
}
}
void poly_mul(int a[],int b[],int len)
{
init(len);
NTT(a,1),NTT(b,1);
for(int i=0;i<lim;i++)a[i]=1ll*a[i]*b[i]%P;
NTT(a,-1);
}
void poly_inv(int a[],int b[],int len)
{
int tmp[maxn]={};
b[0]=fsp(a[0]);
int op=1,ln=1;
while(ln<(len<<1))
{
init(ln);
for(int i=0;i<ln;i++)tmp[i]=a[i];
NTT(tmp,1),NTT(b,1);
for(int i=0;i<lim;i++)b[i]=1ll*(1ll*2*b[i]-1ll*b[i]*b[i]%P*tmp[i]%P+P)%P;
NTT(b,-1);
for(int i=ln;i<lim;i++)b[i]=0;
ln<<=1;
}
}
void poly_sqrt(int a[],int b[],int len)
{
int tmp[maxn]={},H[maxn]={},tmp2[maxn]={};
b[0]=1;
int ln=1;
while(ln<(len<<1))
{
for(int i=0;i<ln;i++)tmp[i]=a[i];
for(int i=0;i<ln;i++)tmp2[i]=2ll*b[i]%P;
poly_inv(tmp2,H,ln);
init(ln);
NTT(b,1),NTT(tmp,1),NTT(H,1);
for(int i=0;i<lim;i++)b[i]=1ll*H[i]%P*(tmp[i]+1ll*b[i]*b[i]%P)%P;
NTT(b,-1);
for(int i=ln;i<lim;i++)b[i]=0;
for(int i=0;i<lim;i++)H[i]=tmp[i]=0;
ln<<=1;
}
}
void poly_deri(int num[],int len)
{
for(int i=0;i<len-1;i++)
{
num[i]=1ll*(i+1)*num[i+1]%P;
}
num[len-1]=0;
}
void poly_intg(int num[],int len)
{
for(int i=len;i>0;i--)
{
num[i]=1ll*num[i-1]*fsp(i)%P;
}
num[0]=0;
}
void poly_Lyin(int a[],int b[],int len)
{
int tmp[maxn]={};
for(int i=0;i<len;i++)tmp[i]=a[i];
poly_inv(tmp,b,len);
poly_deri(tmp,len);
poly_mul(b,tmp,2*len-1);
poly_intg(b,len-1);
}
int a[maxn],b[maxn],n,k,t;
int main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
cin>>n>>k;
b[0]=1;
for(int i=1;i<=n;i++)
{
b[i]=1ll*b[i-1]*(i+k-1)%P*fsp(i)%P;
}
for(int i=0;i<n;i++)
{
cin>>a[i];
a[i]=1ll*a[i]*b[i]%P;
}
poly_mul(a,b,2*n);
for(int i=0;i<n;i++)
{
cout<<a[i]<<" ";
}
return 0;
}
礼物
挺经典的多项式题,比较简单,完全比不上前面几道。(预计越往后越水,因为肝不动了)
假设从第i位开始匹配(已经倍长好了),我们把b翻转
\[\sum_{j=0}^{n+i-1}f_jh_{i-j}
\]
裸的卷积,第n-2n-1项取个最大值就行
代码
#include<bits/stdc++.h>
using namespace std;
const int maxn = 5e5+5e4;
const int P=998244353,g=3,gi=332748118;
int lim=1,r[maxn],c[maxn],w[maxn];
int fsp(int a,int b=P-2)
{
int s=1;
while(b)
{
if(b&1)s=1ll*s*a%P;
b>>=1;
a=1ll*a*a%P;
}
return s;
}
void init(int len)
{
int l=0;
lim=1;
while(lim<=len)lim<<=1,l++;
int wn=fsp(g,(P-1)/lim),cw=fsp(gi,(P-1)/lim);
w[0]=c[0]=1;
for(int i=1;i<lim;i++)
{
r[i]=(r[i>>1]>>1)|((i&1)<<(l-1));
w[i]=1ll*w[i-1]*wn%P;
c[i]=1ll*c[i-1]*cw%P;
}
}
void NTT(int num[],int typ)
{
for(int i=0;i<lim;i++)if(i<r[i])swap(num[i],num[r[i]]);
if(typ==1)
{
for(int m=1,t=(lim>>1);m<lim;m<<=1,t>>=1)
{
for(int i=0;i<lim;i+=(m<<1))
{
for(int j=0;j<m;j++)
{
int x=num[i+j],y=1ll*num[i+j+m]*w[t*j]%P;
num[i+j]=(x+y)%P;
num[i+j+m]=(x-y+P)%P;
}
}
}
}else{
for(int m=1,t=(lim>>1);m<lim;m<<=1,t>>=1)
{
for(int i=0;i<lim;i+=(m<<1))
{
for(int j=0;j<m;j++)
{
int x=num[i+j],y=1ll*num[i+j+m]*c[t*j]%P;
num[i+j]=(x+y)%P;
num[i+j+m]=(x-y+P)%P;
}
}
}
int invlen=fsp(lim);
for(int i=0;i<lim;i++)
{
num[i]=1ll*num[i]*invlen%P;
}
}
}
void poly_mul(int a[],int b[],int len)
{
init(len);
NTT(a,1),NTT(b,1);
for(int i=0;i<lim;i++)a[i]=1ll*a[i]*b[i]%P;
NTT(a,-1);
}
void poly_inv(int a[],int b[],int len)
{
int tmp[maxn]={};
b[0]=fsp(a[0]);
int op=1,ln=1;
while(ln<(len<<1))
{
init(ln);
for(int i=0;i<ln;i++)tmp[i]=a[i];
NTT(tmp,1),NTT(b,1);
for(int i=0;i<lim;i++)b[i]=1ll*(1ll*2*b[i]-1ll*b[i]*b[i]%P*tmp[i]%P+P)%P;
NTT(b,-1);
for(int i=ln;i<lim;i++)b[i]=0;
ln<<=1;
}
}
void poly_sqrt(int a[],int b[],int len)
{
int tmp[maxn]={},H[maxn]={},tmp2[maxn]={};
b[0]=1;
int ln=1;
while(ln<(len<<1))
{
for(int i=0;i<ln;i++)tmp[i]=a[i];
for(int i=0;i<ln;i++)tmp2[i]=2ll*b[i]%P;
poly_inv(tmp2,H,ln);
init(ln);
NTT(b,1),NTT(tmp,1),NTT(H,1);
for(int i=0;i<lim;i++)b[i]=1ll*H[i]%P*(tmp[i]+1ll*b[i]*b[i]%P)%P;
NTT(b,-1);
for(int i=ln;i<lim;i++)b[i]=0;
for(int i=0;i<lim;i++)H[i]=tmp[i]=0;
ln<<=1;
}
}
void poly_deri(int num[],int len)
{
for(int i=0;i<len-1;i++)
{
num[i]=1ll*(i+1)*num[i+1]%P;
}
num[len-1]=0;
}
void poly_intg(int num[],int len)
{
for(int i=len;i>0;i--)
{
num[i]=1ll*num[i-1]*fsp(i)%P;
}
num[0]=0;
}
void poly_Lyin(int a[],int b[],int len)
{
int tmp[maxn]={};
for(int i=0;i<len;i++)tmp[i]=a[i];
poly_inv(tmp,b,len);
poly_deri(tmp,len);
poly_mul(b,tmp,2*len-1);
poly_intg(b,len-1);
}
int a[maxn],b[maxn];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int n,m;
cin>>n>>m;
for(int i=0;i<n;i++)cin>>a[i];
for(int j=0;j<n;j++)cin>>b[j];
int x=0,y=0;
for(int i=0;i<n;i++)x+=a[i]*a[i],y+=a[i];
for(int i=0;i<n;i++)x+=b[i]*b[i],y-=b[i];
int ans=1e9;
for(int i=-m;i<=m;i++)
{
ans=min(ans,n*i*i+2*i*y);
}
ans+=x;
for(int i=0;i<n;i++)a[i+n]=a[i];
reverse(b,b+n);
poly_mul(a,b,3*n);
int maxx=0;
for(int i=n;i<2*n;i++)maxx=max(maxx,a[i]);
cout<<ans-2*maxx;
return 0;
}
CF223C Partial Sums
同前缀和和差分