「十二省联考 2019」皮配
「十二省联考 2019」皮配
传送门
题解
这个题目其实很妙,真的.
首先考虑一个最简单的\(dp\),设\(f_{i,j,k}\)表示前\(i\)个学校,有\(j\)个人选择了蓝阵营,\(k\)个人选择了鸭派系.那么很显然可以背包转移.
如果没有限制,那么可以直接把城市的决策和学校的决策卷积.
这个时候有了限制,还是考虑分开做.你发现这个\(k\)贼小,而且\(s_i\)也很小.
没有限制的学校和城市,可以直接背包出来.
如果有了限制,考虑用最简单的\(dp\)背包,这样子的复杂度就是\(ks\)的一个背包,所以可以过.
代码
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<math.h>
#include<algorithm>
#include<queue>
#include<set>
#include<map>
#include<iostream>
using namespace std;
#define ll long long
#define REP(a,b,c) for(int a=b;a<=c;a++)
#define re register
#define file(a) freopen(a".in","r",stdin);freopen(a".out","w",stdout)
typedef pair<int,int> pii;
#define mp make_pair
inline int gi()
{
int f=1,sum=0;char ch=getchar();
while(ch>'9' || ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0' && ch<='9'){sum=(sum<<3)+(sum<<1)+ch-'0';ch=getchar();}
return f*sum;
}
const int N=1010,M=3010,Mod=998244353;
int n,c,C0,C1,D0,D1,s[N],b[N],S[N],lim[N],LIM[N],g1[M],g2[M],sum,f[M][M],g[M][M],k;
vector<int>G[N];
int calc(int x,int y)
{
int l1=max(0,sum-x-C1),r1=C0-x;
int l2=max(0,sum-y-D1),r2=D0-y;
if(l2>r2||l1>r1)return 0;
return 1ll*(g2[r1]-(l1?g2[l1-1]:0)+Mod)*(g1[r2]-(l2?g1[l2-1]:0)+Mod)%Mod;
}
void solve()
{
n=gi();c=gi();C0=gi();C1=gi();D0=gi();D1=gi();sum=0;
for(int i=1;i<=n;i++)
{
b[i]=gi();s[i]=gi();
sum+=s[i],S[b[i]]+=s[i];
}
k=gi();
for(int i=1;i<=n;i++)lim[i]=-1;
for(int i=1;i<=c;i++)LIM[i]=-1;
for(int i=1;i<=k;i++)
{
int id=gi(),p=gi();lim[id]=LIM[b[id]]=p;
G[b[id]].push_back(id);
}
int s1=0,s2=0;g1[0]=g2[0]=1;
for(int i=1;i<=n;i++)
{
s1+=s[i];if(~lim[i])continue;
for(int j=min(D0,s1);j>=s[i];j--)g1[j]=(g1[j]+g1[j-s[i]])%Mod;
}
for(int i=1;i<=c;i++)
{
s2+=S[i];if(~LIM[i]||!S[i])continue;
for(int j=min(C0,s2);j>=S[i];j--)g2[j]=(g2[j]+g2[j-S[i]])%Mod;
}
for(int i=1;i<=D0;i++)g1[i]=(g1[i]+g1[i-1])%Mod;
for(int i=1;i<=C0;i++)g2[i]=(g2[i]+g2[i-1])%Mod;
s1=s2=0;f[0][0]=1;
for(int u=1;u<=c;u++)
if(~LIM[u]&&S[u])
{
for(int j=0;j<=min(s1,C0);j++)
for(int k=0;k<=min(D0,s2);k++)g[j][k]=f[j][k];
for(int i:G[u])
{
s2+=s[i];
int t0=(lim[i]!=0),t1=(lim[i]!=1),t2=(lim[i]!=2),t3=(lim[i]!=3);
for(int j=min(s1,C0);~j;j--)
for(int k=min(s2,D0);~k;k--)
if(k>=s[i])
{
f[j][k]=(f[j][k]*t1+f[j][k-s[i]]*t0)%Mod;
g[j][k]=(g[j][k]*t3+g[j][k-s[i]]*t2)%Mod;
}
else f[j][k]=f[j][k]*t1,g[j][k]=g[j][k]*t3;
}
s1+=S[u];
for(int j=min(C0,s1);~j;j--)
for(int k=min(D0,s2);~k;k--)
if(j>=S[u])f[j][k]=(f[j-S[u]][k]+g[j][k])%Mod;
else f[j][k]=g[j][k];
}
int ans=0;
for(int j=0;j<=C0;j++)
for(int k=0;k<=D0;k++)
if(f[j][k])ans=(ans+1ll*f[j][k]*calc(j,k)%Mod)%Mod;
printf("%d\n",ans);
for(int j=0;j<=C0;j++)for(int k=0;k<=D0;k++)f[j][k]=g[j][k]=0;
for(int i=0;i<=D0;i++)g1[i]=0;
for(int i=0;i<=C0;i++)g2[i]=0;
for(int i=1;i<=n;i++)s[i]=0;
for(int i=1;i<=c;i++)S[i]=0,G[i].clear();
}
int main()
{
int T=gi();
while(T--)solve();
return 0;
}