bzoj 5498: [2019省队联测]皮配dp
Posted lokiii
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj 5498: [2019省队联测]皮配dp相关的知识,希望对你有一定的参考价值。
是个神仙dp……
参考:https://www.luogu.org/blog/xzz-233/solution-p5289
设f[i][j][k]是前i个有限制的城市,所有学校中选蓝色阵营有j人,有限制的学校中鸭派系有k人的方案数;g[i][j]是前i个没有限制的城市,蓝色阵营有j人的方案数;h[i][j]是前i个没有限制的学校,鸭派系有j人的方案数
f的转移枚举当前阵营
全dp出来之后,把gh前缀和处理,然后一段一段的和f合并加到ans上
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int N=2505,mod=998244353;
int T,n,c,c0,c1,d0,d1,k,m,ss,ans,b[N],s[N],f[N][N],f1[N][N],f2[N][N],g[N],h[N],ki[N],kp[N],v[N],ct[N],sum[N],sm[N];
vector<int>sc[N];
void jia(int &x,int y)
{
if((x+=y)>=mod)
x-=mod;
}
int read()
{
int r=0,f=1;
char p=getchar();
while(p>'9'||p<'0')
{
if(p=='-')
f=-1;
p=getchar();
}
while(p>='0'&&p<='9')
{
r=r*10+p-48;
p=getchar();
}
return r*f;
}
int main()
{
T=read();
while(T--)
{
memset(f,0,sizeof(f));
memset(f1,0,sizeof(f1));
memset(f2,0,sizeof(f2));
memset(g,0,sizeof(g));
memset(h,0,sizeof(h));
memset(sm,0,sizeof(sm));
memset(sum,0,sizeof(sum));
memset(ct,0,sizeof(ct));
for(int i=0;i<N;i++)
sc[i].clear();
ss=0,ans=0;
n=read(),c=read(),c0=read(),c1=read(),d0=read(),d1=read();
for(int i=1;i<=n;i++)
b[i]=read(),s[i]=read(),sum[b[i]]+=s[i],ss+=s[i];
m=k=read();
for(int i=1;i<=n;i++)
v[i]=-1;
for(int i=1;i<=k;i++)
{
ki[i]=read(),kp[i]=read();
ct[i]=b[ki[i]];
sc[b[ki[i]]].push_back(ki[i]);
v[ki[i]]=kp[i];
}
sort(ct+1,ct+1+m);
m=unique(ct+1,ct+1+m)-ct-1;
for(int i=1;i<=n;i++)
if(v[i]!=-1)
sm[b[i]]+=s[i];
f[0][0]=1;
for(int i=1,s1=0,s2=0;i<=m;i++)
{
s1=min(c0,s1+sum[ct[i]]),s2=min(d0,s2+sm[ct[i]]);
for(int o=0;o<=1;o++)
{
for(int j=0;j<=s1;j++)
for(int k=0;k<=s2;k++)
f1[j][k]=f[j][k];
for(int l=0,len=sc[ct[i]].size();l<len;l++)
{
int x=sc[ct[i]][l];
for(int j=s1;j>=0;j--)
for(int k=s2;k>=0;k--)
{
if(o==0)
{
f1[j][k]=0;
if(v[x]!=1&&j>=s[x])
jia(f1[j][k],f1[j-s[x]][k]);
if(v[x]!=0&&j>=s[x]&&k>=s[x])
jia(f1[j][k],f1[j-s[x]][k-s[x]]);
}
else
{
if(v[x]==3)
f1[j][k]=0;
if(v[x]!=2&&k>=s[x])
jia(f1[j][k],f1[j][k-s[x]]);
}
}
}
if(o==0)
{
int nw=sum[ct[i]]-sm[ct[i]];
for(int j=s1;j>=0;j--)
for(int k=s2;k>=0;k--)
{
if(j>=nw)
f1[j][k]=f1[j-nw][k];
else
f1[j][k]=0;
}
for(int j=0;j<=s1;j++)
for(int k=0;k<=s2;k++)
f2[j][k]=f1[j][k];
}
else
{
for(int j=0;j<=s1;j++)
for(int k=0;k<=s2;k++)
f[j][k]=(f1[j][k]+f2[j][k])%mod;
}
}
}
g[0]=1;
for(int i=1,smm=0;i<=c;i++)
if(sc[i].empty()&&sum[i])
{
smm=min(c0,smm+sum[i]);
for(int j=smm;j>=0;j--)
if(j>=sum[i])
jia(g[j],g[j-sum[i]]);
}
h[0]=1;
for(int i=1,smm=0;i<=n;i++)
if(v[i]==-1)
{
smm=min(d0,smm+s[i]);
for(int j=smm;j>=0;j--)
if(j>=s[i])
jia(h[j],h[j-s[i]]);
}
for(int i=1;i<=c0;i++)
jia(g[i],g[i-1]);
for(int i=1;i<=d0;i++)
jia(h[i],h[i-1]);
for(int i=0;i<=c0;i++)
if(ss-i-c1-1<c0-i)
for(int j=0;j<=d0;j++)
if(ss-j-d1-1<d0-j)
jia(ans,1ll*f[i][j]*(g[c0-i]-(ss-i-c1-1>=0?g[ss-i-c1-1]:0)+mod)%mod*(h[d0-j]-(ss-j-d1-1>=0?h[ss-j-d1-1]:0)+mod)%mod);
printf("%d
",(ans+mod)%mod);
}
return 0;
}
以上是关于bzoj 5498: [2019省队联测]皮配dp的主要内容,如果未能解决你的问题,请参考以下文章