巧妙运用“独立”的性质,对于“不独立”的进行暴力处理,再合并
1.dp[i][j][k]前i个城市,蓝有j,鸭有k个方案数
2.无限制时,城市的阵营和学校的派系独立,直接Dp出城市选择方案,派系选择方案,直接乘起来。显然唯一分配且一一对应
有限制,只有30个
考虑对于有限制的城市,优先考虑这些城市的阵营和这个城市中学校的派系分配。
f[i][j][k],前i个有限制的城市,“总共学校占蓝色阵营j个”,有限制的学校占鸭k个
对于没有限制的,
g[i][j]前i个无限制城市,占蓝色阵营j个,
h[i][j]前i个无限制学校,占鸭派系j个
最后枚举j,k,处理出g,h的取值范围,然后乘起来就是方案
考虑每个答案会被统计的位置,显然还是一一对应的。
注意:
1.取mod
2.区间下界可能<0,
3.是“总共学校占蓝色阵营j个”!!!!!!而不是仅考虑限制城市中的限制学校。
mdzz
#include<bits/stdc++.h> #define reg register int #define il inline #define fi first #define se second #define solid const auto & #define mk(a,b) make_pair(a,b) #define numb (ch^'0') using namespace std; typedef long long ll; template<class T>il void rd(T &x){ char ch;x=0;bool fl=false; while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true); for(x=numb;isdigit(ch=getchar());x=x*10+numb); (fl==true)&&(x=-x); } template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');} template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');} template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('\n');} namespace Miracle{ const int M=2503; const int N=1003; const int mod=998244353; int n,m,c,K; int f[M][M],g[M],h[M],p[M][M],q[M][M],s[N]; int b[N]; int C0,C1,D0,D1; vector<int>city[N]; // int sz[N]; int no[N],has[N]; int ad(int x,int y){ return x+y>=mod?x+y-mod:x+y; } void cpy(int f[M][M],int g[M][M],int a,int b){ for(reg i=0;i<=a;++i){ for(reg j=0;j<=b;++j){ f[i][j]=g[i][j]; } } } void clear(){ memset(f,0,sizeof f); memset(h,0,sizeof h); memset(g,0,sizeof g); memset(has,0,sizeof has); // memset(sz,0,sizeof sz); memset(no,-1,sizeof no); for(reg i=1;i<=n;++i){ city[i].clear(); } } int main(){ int t;rd(t); while(t--){ clear(); rd(n);rd(c); rd(C0);rd(C1);rd(D0);rd(D1); int sum=0; for(reg i=1;i<=n;++i){ rd(b[i]);rd(s[i]);sum+=s[i]; has[b[i]]+=s[i]; // city[b[i]].push_back(i); } // memset(no,-1,sizeof no); // memset(sz,0,sizeof sz); // memset(has,0,sizeof has); rd(K); int x; for(reg i=1;i<=K;++i){ rd(x);rd(no[x]); city[b[x]].push_back(x); // sz[b[x]]+=s[x]; } f[0][0]=1; int now=0; for(reg o=1;o<=c;++o){ if(city[o].size()==0) continue; int sum1=min(C0,now+has[o]); int sum2=min(D0,now+has[o]); // cout<<" sum1 "<<sum1<<" "<<sum2<<endl; cpy(p,f,sum1,sum2); // sum1=min(C0,now);sum2=min(D0,now); for(auto id:city[o]){//C0 // sum1=min(C0,sum1+has[id]); // sum2=min(D0,sum2+has[id]); for(reg i=sum1;i>=0;--i){ for(reg j=sum2;j>=0;--j){ int lp=p[i][j]; p[i][j]=0; if(no[id]!=0){ p[i][j]=ad(p[i][j],p[i][j-s[id]]); } if(no[id]!=1){ p[i][j]=ad(p[i][j],lp); } } } } // cout<<" sum1 "<<sum1<<" sum "<<sum2<<endl; for(reg i=sum1;i>=0;--i){ for(reg j=sum2;j>=0;--j){ p[i][j]=0; if(i>=has[o]) { // cout<<" hahah "<<o<<" "<<p[i-has[o]][j]<<endl; p[i][j]=p[i-has[o]][j]; } } } cpy(q,f,sum1,sum2); sum1=min(C0,now+has[o]); sum2=min(D0,now+has[o]); for(auto id:city[o]){//C1 // sum1=min(C0,sum1+has[id]); // sum2=min(D0,sum2+has[id]); for(reg i=sum1;i>=0;--i){ for(reg j=sum2;j>=0;--j){ int lp=q[i][j]; q[i][j]=0; // if(i>=s[id]){ if(j>=s[id]&&no[id]!=2){ q[i][j]=ad(q[i][j],q[i][j-s[id]]); } if(no[id]!=3){ q[i][j]=ad(q[i][j],lp); } // } } } } for(reg i=0;i<=sum1;++i){ for(reg j=0;j<=sum2;++j){ f[i][j]=ad(p[i][j],q[i][j]); } } now+=has[o]; } // for(reg i=0;i<=C0;++i){ // for(reg j=0;j<=D0;++j){ // cout<<i<<" "<<j<<" : "<<f[i][j]<<endl; // } // }cout<<endl; g[0]=1; int S=0; for(reg i=1;i<=c;++i){ if(city[i].size()) continue; if(!has[i]) continue; S=min(C0,S+has[i]); for(reg j=S;j>=0;--j){ if(j>=has[i]) g[j]=ad(g[j-has[i]],g[j]); } } h[0]=1; S=0; for(reg i=1;i<=n;++i){ if(no[i]!=-1) continue; S=min(D0,S+s[i]); for(reg j=S;j>=0;--j){ if(j>=s[i]) h[j]=ad(h[j-s[i]],h[j]); } } // prt(g,0,C0); // prt(h,0,D0); for(reg i=1;i<=C0;++i) g[i]=ad(g[i],g[i-1]); for(reg i=1;i<=D0;++i) h[i]=ad(h[i],h[i-1]); ll ans=0; for(reg i=0;i<=C0;++i){ for(reg j=0;j<=D0;++j){ int l1=sum-i-C1-1,h1=C0-i; int l2=sum-j-D1-1,h2=D0-j; if(l1>=h1||l2>=h2) continue; // if((ll)f[i][j]*ad(g[h1],mod-g[l1])%mod*ad(h[h2],mod-h[l2])) { // cout<<" i "<<i<<" j "<<j<<" con "<<(ll)f[i][j]*ad(g[h1],mod-g[l1])%mod*ad(h[h2],mod-h[l2])<<endl; // cout<<" nc "<<f[i][j]<<" g1 "<<ad(g[h1],mod-g[l1])<<" h1 "<<ad(h[h2],mod-h[l2])<<endl; // cout<<endl; // } ans=ad(ans,(ll)f[i][j]*ad(g[h1],mod-((l1>=0)?g[l1]:0))%mod*ad(h[h2],mod-((l2>=0)?h[l2]:0))%mod); } } cout<<ans<<endl; } return 0; } } signed main(){ Miracle::main(); return 0; } /* Author: *Miracle* */