题解 求和

传送门

嗯三个小时刚不出来一个题实锤了

发现是对杨辉三角的若干列执行“隔一行统计一个”的操作
Excel 怎么让行列号从 0 开始啊
image
发现组合数 \(\binom{n}{k}\)\(k\) 次多项式
那么第 \(i\) 列要求的这个东西是 \(i+1\) 次多项式
不知道为什么
那么答案是以 \(n\) 为自变量的 \(m+1\) 次多项式
于是可以拉格朗日插值
需要预处理 \(nm\) 个点的组合数怎么办呢?
NTT 优化即可
要求模数是质数才可以做

然后正解:
发现一整列的和是容易求的
现在强制 \(n\) 是奇数,令 \(f_i\) 为第 \(i\) 列的答案
来康康一整列的和等于什么
image
image
image
根据上面演示的过程发现有递推式

\[f_i=\frac{\binom{n+1}{i+1}-f_{i-1}}{2} \]

将模数拆成 \(s2^t\),分别模这两个做再 CRT 合并即可
\(2^t\) 怎么做呢?
\(f_i\) 代入 \(f_{i+1}\),得到

\[f_i=\sum\limits_{j\geqslant i+2}(-2)^{j-(i+2)}\binom{n+1}{j} \]

发现这个东西在 \(j\geqslant i+2+t\) 时同余于 0 所以可以做了
复杂度 \(O(n\log^2 n)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 2000010
#define fir first
#define sec second
#define pb push_back
#define ll long long
//#define int long long

char buf[1<<21], *p1=buf, *p2=buf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf, 1, 1<<21, stdin)), p1==p2?EOF:*p1++)
inline int read() {
	int ans=0, f=1; char c=getchar();
	while (!isdigit(c)) {if (c=='-') f=-f; c=getchar();}
	while (isdigit(c)) {ans=(ans<<3)+(ans<<1)+(c^48); c=getchar();}
	return ans*f;
}

int n, m;
ll mod;
inline ll qpow(ll a, ll b) {ll ans=1; for (; b; a=a*a%mod,b>>=1) if (b&1) ans=ans*a%mod; return ans;}

namespace force{
	// ll x[200010], y[200010];
	// ll fac[200010], inv[200010], ans;
	// inline ll C(int n, int k) {return n<k?0:fac[n]*inv[k]%mod*inv[n-k]%mod;}
	// inline ll lucas(int n, int k) {return !k?1:lucas(n/mod, k/mod)*C(n%mod, k%mod)%mod;}
	ll **C, ans;
	void solve() {
		// fac[0]=fac[1]=1; inv[0]=inv[1]=1;
		// for (int i=2; i<=min((ll)n, mod); ++i) fac[i]=fac[i-1]*i%mod;
		// for (int i=2; i<=min((ll)n, mod); ++i) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
		// for (int i=2; i<=min((ll)n, mod); ++i) inv[i]=inv[i-1]*inv[i]%mod;
		C=new ll*[n+10];
		for (int i=0; i<=n+1; ++i) {
			C[i]=new ll[n+10];
			for (int j=0; j<=n+1; ++j) C[i][j]=0;
		}
		for (int i=0; i<=n; ++i) {
			C[i][0]=1;
			for (int j=1; j<=i; ++j) C[i][j]=(C[i-1][j]+C[i-1][j-1])%mod;
		}
		for (int i=0; i<=n; i+=2)
			for (int j=0; j<=m; j+=2) if (j<=i)
				ans=(ans+C[i][j])%mod;
		printf("%lld\n", ans);
	}
}

// namespace task1{
// 	ll x[N], y[N];
// 	ll fac[N], inv[N], ans;
// 	inline ll C(int n, int k) {return n<k?0:fac[n]*inv[k]%mod*inv[n-k]%mod;}
// 	struct poly{
// 		int n;
// 		ll a[N], b[N], c[N], f[N];
// 		void lagrange() {
// 			for (int i=1; i<=n+1; ++i) {
// 				a[i]=1;
// 				for (int j=1; j<=n+1; ++j) if (i!=j) a[i]=a[i]*(x[i]-x[j])%mod;
// 				a[i]=y[i]*qpow(a[i], mod-2)%mod;
// 			}
// 			b[0]=1;
// 			for (int i=1; i<=n+1; ++i) {
// 				for (int j=i; j; --j) b[j]=(b[j-1]-x[i]*b[j])%mod;
// 				b[0]=-x[i]*b[0]%mod;
// 			}
// 			for (int i=1; i<=n+1; ++i) {
// 				ll inv=qpow(x[i], mod-2);
// 				if (!inv) for (int j=0; j<=n; ++j) c[j]=b[j+1];
// 				else {
// 					c[0]=-b[0]*inv%mod;
// 					for (int j=1; j<=n; ++j) c[j]=(c[j-1]-b[j])*inv%mod;
// 				}
// 				for (int j=0; j<=n; ++j) f[j]=(f[j]+a[i]*c[j])%mod;
// 			}
// 			// cout<<"f: "; for (int i=0; i<=n; ++i) cout<<f[i]<<' '; cout<<endl;
// 		}
// 		ll qval(ll k) {
// 			ll ans=0;
// 			for (int i=n; ~i; --i) ans=(ans*k+f[i])%mod;
// 			return (ans%mod+mod)%mod;
// 		}
// 	}pl;
// 	void solve() {
// 		fac[0]=fac[1]=1; inv[0]=inv[1]=1;
// 		for (int i=2; i<=min((ll)m+10000, mod); ++i) fac[i]=fac[i-1]*i%mod;
// 		for (int i=2; i<=min((ll)m+10000, mod); ++i) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
// 		for (int i=2; i<=min((ll)m+10000, mod); ++i) inv[i]=inv[i-1]*inv[i]%mod;
// 		// for (int j=0; j<=m; j+=2)
// 		// 	for (int i=0; i<=m; ++i)
// 		// 		y[i+1]=(y[i+1]+C(i, j));
// 		// for (int i=0; i<=m; ++i) x[i+1]=i;
// 		// for (int i=1; i<=m; i+=2) y[i+1]=0;
// 		// for (int i=1; i<=m+1; ++i) y[i]=(y[i-1]+y[i])%mod;
// 		// pl.n=m+1; pl.lagrange();

// 		// m=20;
// 		// int lim=m+1;
// 		// for (int i=1; i<=lim; ++i) x[i]=i;
// 		// for (int i=2; i<=lim*2; i+=2) y[i/2]=C(i, m);
// 		// cout<<"y: "; for (int i=1; i<=lim; ++i) cout<<y[i]<<' '; cout<<endl;
// 		// for (int i=1; i<=lim; ++i) y[i]=(y[i-1]+y[i])%mod;
// 		// // for (int i=1; i<=2*m+1; ++i) x[i]=i, y[i]=C(i, m);
// 		// // for (int i=1; i<=2*m+1; i+=2) y[i]=0;
// 		// pl.n=lim; pl.lagrange();
// 		// // cout<<pl.qval(n)<<endl;
// 		// ll lst=0;
// 		// for (int i=0; i<=1000; i+=2) cout<<(lst=(lst+C(i, m))%mod)<<' '; cout<<endl;
// 		// for (int i=0; i<=1000; i+=2) cout<<pl.qval(i/2)<<' '; cout<<endl;

// 		// int lim=m+1;
// 		// for (int n=2; n<=lim*2; n+=2) {
// 		// 	for (int j=0; j<=m; j+=2) {
// 		// 		for (int k=0; k<=n; k+=2) {
// 		// 			y[n/2]=(y[n/2]+C(k, j))%mod;
// 		// 		}
// 		// 	}
// 		// }
// 		// // cout<<"y: "; for (int i=1; i<=n; ++i) co
// 		// for (int i=1; i<=lim; ++i) x[i]=i;
// 		// pl.n=lim; pl.lagrange();
// 		// cout<<pl.qval(n/2)<<endl;
// 		// // for (int i=1; i<=20; ++i) cout<<pl.qval(i)<<' '; cout<<endl;

// 		int lim=m+2;
// 		for (int j=0; j<=m; j+=2)
// 			for (int i=0; i<=lim*2; i+=2)
// 				y[i/2]=(y[i/2]+C(i, j))%mod;
// 		for (int i=1; i<=lim; ++i) x[i]=i;
// 		for (int i=1; i<=lim; ++i) y[i]=(y[i-1]+y[i])%mod;
// 		// cout<<"x: "; for (int i=1; i<=lim; ++i) cout<<x[i]<<' '; cout<<endl;
// 		// cout<<"y: "; for (int i=1; i<=lim; ++i) cout<<y[i]<<' '; cout<<endl;
// 		pl.n=m+1; pl.lagrange();
// 		cout<<pl.qval(n/2)<<endl;
// 		// ll tem=0;
// 		// for (int i=0; i<=n; i+=2)
// 		// 	for (int j=0; j<=m; j+=2)
// 		// 		tem=(tem+C(i, j))%mod;
// 		// cout<<tem<<endl;
// 	}
// }

namespace task2{
	int rev[N];
	ll x[2000010], y[2000010];
	ll fac[2000010], inv[2000010], ans;
	const ll mod=998244353, rt=3, phi=mod-1;
	inline ll C(int n, int k) {return n<k?0:fac[n]*inv[k]%mod*inv[n-k]%mod;}
	struct lagr{
		int n;
		ll pre[N], suf[N], inv[N];
		ll lagrange(ll* y, ll k) {
			pre[0]=suf[n+1]=inv[0]=inv[1]=1;
			for (int i=1; i<=n; ++i) pre[i]=pre[i-1]*(k-i)%mod;
			for (int i=n; i; --i) suf[i]=suf[i+1]*(k-i)%mod;
			for (int i=2; i<=n; ++i) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
			for (int i=2; i<=n; ++i) inv[i]=inv[i-1]*inv[i]%mod;
			ll ans=0;
			for (int i=1; i<=n; ++i) ans=(ans+((n-i)&1?-1:1)*y[i]*pre[i-1]%mod*suf[i+1]%mod*inv[i-1]%mod*inv[n-i]%mod)%mod;
			return (ans%mod+mod)%mod;
		}
	}pl;
	struct poly{
		vector<ll> a;
		int len() {return a.size();}
		void resize(int t) {a.resize(t);}
		ll& operator [] (int t) {return a[t];}
		void clr(int len) {for (int i=0; i<len; ++i) a[i]=0;}
		void cpy(poly& a, poly& b, int len) {for (int i=0; i<len; ++i) a[i]=b[i];}
		void mul(poly& a, poly& b, int len) {for (int i=0; i<len; ++i) a[i]=a[i]*b[i]%mod;}
		void adjust() {while (a.size()&&!a.back()) a.pop_back();}
		void ntt(int len, int op) {
			int bct=ceil(log2(len));
			for (int i=0; i<len; ++i) rev[i]=(rev[i>>1]>>1)|((i&1)<<(bct-1));
			for (int i=0; i<len; ++i) if (i<rev[i]) swap(a[i], a[rev[i]]);
			ll w, wn, t;
			for (int i=1; i<len; i<<=1) {
				wn=qpow(rt, (op*phi/(i<<1)+phi)%phi);
				for (int j=0,step=i<<1; j<len; j+=step) {
					w=1;
					for (int k=j; k<j+i; ++k,w=w*wn%mod) {
						t=a[k+i]*w%mod;
						a[k+i]=(a[k]-t)%mod;
						a[k]=(a[k]+t)%mod;
					}
				}
			}
			if (op==-1) {
				ll inv=qpow(len, mod-2);
				for (int i=0; i<len; ++i) a[i]=a[i]*inv%mod;
			}
		}
		poly operator * (poly b) {
			poly t1=*this, t2=b;
			int len, n=t1.len()+t2.len()-1;
			for (len=1; len<=n; len<<=1) ;
			t1.resize(len); t2.resize(len);
			t1.ntt(len, 1); t2.ntt(len, 1);
			mul(t1, t2, len);
			t1.ntt(len, -1);
			t1.adjust();
			return t1;
		}
	}f, g;
	void solve() {
		// cout<<double(sizeof(fac)*4.5+sizeof(rev)*5)/1000/1000<<endl;
		fac[0]=fac[1]=1; inv[0]=inv[1]=1;
		for (int i=2; i<=min((ll)(m+2)*2, mod); ++i) fac[i]=fac[i-1]*i%mod;
		for (int i=2; i<=min((ll)(m+2)*2, mod); ++i) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
		for (int i=2; i<=min((ll)(m+2)*2, mod); ++i) inv[i]=inv[i-1]*inv[i]%mod;
		int lim=m+2;
		// for (int j=0; j<=m; j+=2)
		// 	for (int i=0; i<=lim*2; i+=2)
		// 		y[i/2]=(y[i/2]+C(i, j))%mod;
		for (int i=0; i<=m; ++i) f.a.pb(i%2?0:inv[i]);
		for (int i=0; i<=lim*2; ++i) g.a.pb(i%2?0:inv[i]);
		f=f*g;
		for (int i=0; i<=lim*2; i+=2) y[i/2]=f[i]*fac[i]%mod;
		for (int i=1; i<=lim; ++i) x[i]=i;
		for (int i=1; i<=lim; ++i) y[i]=(y[i-1]+y[i])%mod;
		// cout<<"x: "; for (int i=1; i<=lim; ++i) cout<<x[i]<<' '; cout<<endl;
		// cout<<"y: "; for (int i=1; i<=lim; ++i) cout<<y[i]<<' '; cout<<endl;
		pl.n=lim;
		cout<<pl.lagrange(y, n/2)<<endl;
	}
}

namespace task{
	ll fac[N], inv[N];
	bool npri[N], vis[N];
	vector<pair<ll, ll>> vec;
	vector<int> div1[N], div2[N];
	int pri[N], sta[N], p[N], top, pcnt, t;
	ll dat[N<<2], cnt[N<<2], f[N], rec[N], ans, binom=1;
	inline ll C(int n, int k) {return n<k?0:fac[n]*inv[k]%mod*inv[n-k]%mod;}
	void exgcd(ll a, ll b, ll& x, ll& y) {
		if (!b) {x=1; y=0; return ;}
		exgcd(b, a%b, y, x);
		y-=a/b*x;
	}
	ll qinv(ll a) {/* cout<<"qinv: "<<a<<endl; */ ll x, y; exgcd(a, mod, x, y); /* cout<<"return: "<<x<<endl; */ return x;}
	void add(int x) {
		// cout<<"add: "<<x<<endl;
		for (auto it:div1[n+1-x]) {
			// cout<<"x: "<<x<<endl;
			// cout<<"it: "<<it<<endl;
			int w=0, val=1;
			for (; !(x%it); x/=it,++w,val*=it);
			if (vis[it]) sta[it]+=w;
			else binom=binom*val%mod;
		}
		binom=binom*x%mod;
	}
	void del(int x) {
		// cout<<"del: "<<x<<endl;
		for (auto it:div2[x]) {
			// cout<<"x: "<<x<<endl;
			// cout<<"it: "<<it<<endl;
			int w=0, val=1;
			for (; !(x%it); x/=it,++w,val*=it);
			if (vis[it]) sta[it]-=w;
			else binom=binom*qinv(val)%mod;
		}
		// cout<<"x: "<<x<<endl;
		binom=binom*qinv(x)%mod;
	}
	void add2(int x) {
		for (auto it:div2[x]) {
			int w=0, val=1;
			for (; !(x%it); x/=it,++w,val*=it);
			if (vis[it]) sta[it]+=w;
			else binom=binom*val%mod;
		}
		binom=binom*x%mod;
	}
	void del2(int x) {
		for (auto it:div1[n+1-x]) {
			int w=0, val=1;
			for (; !(x%it); x/=it,++w,val*=it);
			if (vis[it]) sta[it]-=w;
			else binom=binom*qinv(val)%mod;
		}
		binom=binom*qinv(x)%mod;
	}
	ll qval() {ll ans=binom; for (int i=1; i<=top; ++i) ans=ans*qpow(p[i], sta[p[i]])%mod; return ans;}
	ll crt() {
		ll ans=0, M=vec[0].sec*vec[1].sec;
		for (int i=0; i<2; ++i) {
			ll w=M/vec[i].sec, x, y;
			exgcd(w, vec[i].sec, x, y);
			ans=(ans+vec[i].fir*w*x)%M;
		}
		return (ans%M+M)%M;
	}
	void solve() {
		m=min(m, n|=1);
		// fac[0]=fac[1]=1; inv[0]=inv[1]=1;
		// for (int i=2; i<=n+10; ++i) fac[i]=fac[i-1]*i%mod;
		// for (int i=2; i<=n+10; ++i) inv[i]=(mod-mod/i)*inv[mod%i]%mod;
		// for (int i=2; i<=n+10; ++i) inv[i]=inv[i-1]*inv[i]%mod;
		for (t=0; !(mod&1); ++t,mod>>=1);
		// cout<<"mod: "<<mod<<' '<<(1<<t)<<endl;
		for (int i=2; i<=m+1; ++i) {
			if (!npri[i]) pri[++pcnt]=i;
			for (int j=1; j<=pcnt&&i*pri[j]<=m+1; ++j) {
				npri[i*pri[j]]=1;
				if (!(i%pri[j])) break;
			}
		}
		// f[0]=(n+1)>>1;
		// for (int i=1; i<=m; ++i) f[i]=(C(n+1, i+1)-f[i-1])*qpow(2, mod-2)%mod;
		// ll ans=0;
		// for (int i=0; i<=m; i+=2) ans=(ans+f[i])%mod;
		// cout<<"f: "; for (int i=0; i<=m; ++i) cout<<f[i]<<' '; cout<<endl;
		// cout<<(ans%mod+mod)%mod<<endl;
		// build(1, 1, pcnt);
		for (int i=1; i<=pcnt; ++i) if (mod%pri[i]==0) vis[p[++top]=pri[i]]=1;
		for (int i=1; i<=top; ++i)
			for (int j=(n-m)/p[i]; p[i]*j<=n+1; ++j)
				div1[n+1-p[i]*j].pb(p[i]);
		for (int i=1; i<=top; ++i)
			for (int j=1; p[i]*j<=m+1; ++j)
				div2[p[i]*j].pb(p[i]);
		f[0]=((n+1)>>1)%mod; add(n+1);
		const ll inv2=qinv(2);
		for (int i=1; i<=m; ++i) {
			add(n+1-i); del(i+1);
			f[i]=(qval()-f[i-1])*inv2%mod;
		}
		for (int i=0; i<=m; i+=2) ans=(ans+f[i])%mod;
		// cout<<"f: "; for (int i=0; i<=m; ++i) cout<<f[i]<<' '; cout<<endl;
		// cout<<(ans%mod+mod)%mod<<endl;
		vec.pb({ans, mod});
		// cout<<"ans: "<<(ans%mod+mod)%mod<<endl;
		ans=0; mod=1<<t; binom=1;
		while (top) vis[p[top--]]=0;
		vis[p[++top]=2]=1;
		for (int i=1; i<=m+1; ++i) div1[i].clear(), div2[i].clear();
		for (int i=1; i<=top; ++i)
			for (int j=(n-m-2-t)/p[i]; p[i]*j<=n+2; ++j)
				div1[n+1-p[i]*j].pb(p[i]);
		for (int i=1; i<=top; ++i)
			for (int j=1; p[i]*j<=m+2+t; ++j)
				div2[p[i]*j].pb(p[i]);
		int now=0;
		for (int i=0; i<=m+2+t; ++i) {
			// cout<<"i: "<<i<<endl;
			// cout<<"sta: "<<sta[2]<<endl;
			rec[i]=qval();
			if (n+1==i) break;
			add(n+1-i), del(i+1);
		}
		// cout<<"rec: "; for (int i=0; i<=m+2+t; ++i) cout<<rec[i]<<' '; cout<<endl;
		for (int i=0; i<=m; ++i) if (i+2<=n+1) {
			f[i]=0;
			// for (; now>i+2; --now) del2(n+2-now), add2(now);
			// for (; now<i+2; ++now) add(n+1-now), del(now+1);
			for (int now=i+2; now<i+2+t; ++now) {
				// if (rec[now]&&(qval()%mod+mod)%mod!=(rec[now]%mod+mod)%mod) cout<<qval()<<' '<<rec[now]<<endl;
				// assert(!rec[now] || (qval()%mod+mod)%mod==(rec[now]%mod+mod)%mod);
				f[i]=(f[i]+qpow(-2, now-(i+2))*rec[now])%mod;
				// rec[now]=qval();
				if (n+1==now) break;
				// add(n+1-now), del(now+1);
			}
			if (!(i&1)) ans=(ans+f[i])%mod;
		}
		vec.pb({ans, mod});
		// cout<<"ans: "<<(ans%mod+mod)%mod<<endl;
		printf("%lld\n", crt());
	}
}

signed main()
{
	n=read(); m=read(); mod=read();
	// force::solve();
	// task1::solve();
	// task2::solve();
	// if (mod==998244353) task2::solve();
	// else force::solve();
	task::solve();

	return 0;
}
posted @ 2022-06-06 07:11  Administrator-09  阅读(2)  评论(0编辑  收藏  举报