1 条题解
-
0
自动搬运
来自洛谷,原作者为

dead_X
Still we rise搬运于
2025-08-24 22:30:28,当前版本为作者最后更新于2021-04-07 09:33:54,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
思路
下文记 。
显然如果答案存在,我们放完所有兵营后必定还剩下 个空位置。
因此,我们只需要在 个位置中,有序地选出 个,依次将这些位置钦定为第 个兵营,剩余位置定为空地,即可算出所有方法数。
考虑钦定两侧兵营的 。
若最左侧为第 个兵营,最右侧为第 个兵营,将 向左延长 格子,向右延长 个格子,同时让所有兵营的摆放条件仍然按照 时的条件计数,方法仍然可以形成一一对应,只需要将延长出来的格子去掉即可。
因此,我们可以做到 ,但是过不去。
注意到 的值域只有 ,我们可以转而枚举 ,这样的复杂度为 ,即可通过。
代码
//愿神 zhoukangyang 指引我。 #include<bits/stdc++.h> #define int long long using namespace std; inline int read(){ int s=0,w=1; char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();} while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar(); return s*w; } int a[1000003],b[1000003]; const int p=998244353; int n=read(),m=read(),op=read(); int qp(int x,int y) { int res=1; for(int t=x; y; y>>=1,t=t*t%p) if(y&1) res=res*t%p; return res; } int fac[1000003],ifac[1000003]; int A(int n,int m) { if(n<m) return 0; return fac[n]*ifac[n-m]%p; } int C(int n,int m) { if(n<m) return 0; return fac[n]*ifac[n-m]%p*ifac[m]%p; } void solve0() { int s=0; for(int i=1; i<=n; ++i) s+=a[i]; if(s>m) { puts("0"); return ; } int A=(m-s)+n,ans=1; for(int i=A; i>A-n; --i) ans=ans*i%p; printf("%lld\n",ans); return ; } int G[2003],S[1003]; void solve1() { if(n==1) { printf("%lld\n",m); return ; } int s=0; fac[0]=ifac[0]=1; for(int i=1; i<=m; ++i) fac[i]=fac[i-1]*i%p,ifac[i]=qp(fac[i],p-2); for(int i=1; i<=n; ++i) s+=a[i]; int ans=0; for(int i=1; i<=n; ++i) { for(int j=0; j<=1000; ++j) G[b[i]+j]=(G[b[i]+j]+S[j])%p; ++S[b[i]]; } for(int i=0; i<=2000; ++i) if(G[i]) ans=(ans+G[i]*A(m+i-s+n,n)%p)%p; printf("%lld\n",ans*qp(C(n,n-2),p-2)%p); return ; } signed main() { for(int i=1; i<=n; i++) b[i]=read(),a[i]=(b[i]<<1)-1,--b[i]; if(op) solve1(); else solve0(); return 0; }
- 1
信息
- ID
- 6010
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 4
- 标签
- 递交数
- 0
- 已通过
- 0
- 上传者