多项式题

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

同前缀和和差分

posted @ 2022-10-09 09:38  artalter  阅读(66)  评论(9)    收藏  举报