题解 求和
嗯三个小时刚不出来一个题实锤了
发现是对杨辉三角的若干列执行“隔一行统计一个”的操作
Excel 怎么让行列号从 0 开始啊
发现组合数 \(\binom{n}{k}\) 是 \(k\) 次多项式
那么第 \(i\) 列要求的这个东西是 \(i+1\) 次多项式
不知道为什么
那么答案是以 \(n\) 为自变量的 \(m+1\) 次多项式
于是可以拉格朗日插值
需要预处理 \(nm\) 个点的组合数怎么办呢?
NTT 优化即可
要求模数是质数才可以做
然后正解:
发现一整列的和是容易求的
现在强制 \(n\) 是奇数,令 \(f_i\) 为第 \(i\) 列的答案
来康康一整列的和等于什么
根据上面演示的过程发现有递推式
\[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;
}