「KDOI-03」构造数组 题解
dAniel_lele · · 题解
测试点 1~3
输出不可以,总司令
测试点 4~5
输出
测试点 6~8
暴力,咋暴力都行,数据太小了。
测试点 9~11
这个可以用状压
测试点 12~14
稍微转化一下,转化为:
有
考虑对于每个人选搭档,第
测试点 15~18
状压 dp,考虑每次操作已经选个
测试点 19~25
发现不同操作位置本质相同,首先考虑
容易发现只需要记录
然后分析一下,实际上操作位置只有
代码
#include <bits/stdc++.h>
using namespace std;
const int mod=998244353;
int qp(int a,int b){
int ans=1;
while(b){
if(b&1) ans=((long long)ans*a)%mod;
a=((long long)a*a)%mod;
b>>=1;
}
return ans;
}
int fac[100005],inv[100005];
void init(){
fac[0]=1;
for(int i=1;i<=100000;i++) fac[i]=(long long)fac[i-1]*i%mod;
inv[100000]=qp(fac[100000],mod-2);
for(int i=99999;i>=0;i--) inv[i]=(long long)inv[i+1]*(i+1)%mod;
}
int C(int i,int j){
if(i<0||j<0||i<j) return 0;
return (long long)fac[i]*inv[i-j]%mod*inv[j]%mod;
}
int b[50005],n,pre[50005],dp[2][50005];
signed main(){
init();
cin>>n;
for(int i=1;i<=n;i++) cin>>b[i],pre[i]=pre[i-1]+b[i];
if(pre[n]%2==1) return cout<<0,0;
int sum=pre[n]/2;
dp[0][0]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<=sum;j++){
int tp2=j,tp1=pre[i-2]-j*2,tp0=sum-tp2-tp1;
if(tp0<0) continue;
dp[i&1][j]=0;
}
for(int j=0;j<=sum;j++){
int tp2=j,tp1=pre[i-1]-j*2,tp0=sum-tp2-tp1;
if(tp0<0) continue;
for(int k=0;k<=b[i];k++){
if(tp1<k||tp0<b[i]-k) continue;
if(dp[(i&1)^1][tp2]) (dp[i&1][tp2+k]+=(long long)dp[(i&1)^1][tp2]*C(tp1,k)%mod*C(tp0,b[i]-k)%mod)%=mod;
}
}
}
cout<<dp[n&1][sum];
return 0;
}