「十二省聯考 2019」皮配


題目大意

avatar

題解

首先,可以想到一個\(O(n*m^2)\)的暴力(雖然我考試時沒想到)。將學校按所屬城市排序,記\(f[x][ty][i][j]\)為前x個學校,前一個學校選擇了ty陣營,此時藍有i個人,鴨派有j個人的方案數。如果\(x\)\((x-1)\)在同一個城市,那么必須選同陣營。
然后膜題解分析\(k=0\)的情況,發現選陣營和選派系可以分開算!哇smg。。。背包一下然后直接把兩次算的方案數乘起來就行了。。
\(k>0\) 的時候,發現有一些學校不能在選某派的同時加入某陣營。但是其他學校選陣營和選派系似乎還是可以分開算。。。於是把未強制的學校按照上一種方法背包一下派系;沒有學校被強制的城市也背包一下陣營。。其實就是前兩種算法合起來。。。對於有被強制的城市,注意在選擇一個陣營以后要把這個城市所有學校全部加入該陣營。。
具體實現見代碼。。。
時間復雜度\(O(T*(c*m+n*m+k^2*m\)*10\())\)

代碼

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int Q=2555;
int F[Q],G[Q];
int f[2][2][Q][Q];
struct dt{
	int bel,num,dis;
}p1[Q],p2[Q];
bool operator<(dt a,dt b)
{return a.bel<b.bel;}
int bl[Q],val[Q],ops[Q],gg[Q];
const int MOD=998244353;
inline void Add(int &a,int b)
{a+=b;a>=MOD?a-=MOD:1;}
inline int sub(int a,int b)
{a-=b;return a<0?a+MOD:a;}
inline int mul(int a,int b)
{return 1LL*a*b%MOD;}
int rev[Q];
int GG(int l,int r)
{return l>r?0:(l?sub(G[r],G[l-1]):G[r]);}
int GF(int l,int r)
{return l>r?0:(l?sub(F[r],F[l-1]):F[r]);}
void solve()
{
	int c0,c1,d0,d1;
	int tp1=0,tp2=0;
	int n,c;
	int sum=0;
	scanf("%d%d",&n,&c);
	scanf("%d%d%d%d",&c0,&c1,&d0,&d1);
	for(int i=1;i<=c;i++)gg[i]=0;
	for(int i=1;i<=n;i++){
		ops[i]=-1;
		scanf("%d%d",&bl[i],&val[i]);
		gg[bl[i]]+=val[i];
		sum+=val[i];
	}
	int sss;
	for(scanf("%d",&sss);sss;--sss){
		int x;
		scanf("%d",&x);
		scanf("%d",&ops[x]);
	}
	for(int i=1;i<=n;i++)
		(ops[i]>=0?p1[++tp1]:p2[++tp2])=(dt){bl[i],val[i],ops[i]};
	sort(p1+1,p1+tp1+1),sort(p2+1,p2+tp2+1);
	for(int i=1;i<=tp1;i++){
		if(gg[p1[i].bel]<0)rev[i]=0;
		else rev[i]=gg[p1[i].bel],gg[p1[i].bel]=-1;
	}
//
	G[0]=1;
	for(int i=1;i<=c0;i++)G[i]=0;
	for(int i=1;i<=c;i++)
		if(gg[i]>0)
			for(int j=c0;j>=gg[i];--j)
				Add(G[j],G[j-gg[i]]);
	
	for(int i=1;i<=c0;i++)
		Add(G[i],G[i-1]);
//
	F[0]=1;
	for(int i=1;i<=d0;i++)F[i]=0;
	for(int i=1;i<=tp2;i++){
		int Num=p2[i].num;
		for(int j=d0;j>=Num;--j)
			Add(F[j],F[j-Num]);
	}
	for(int i=1;i<=d0;i++)
		Add(F[i],F[i-1]);
	//
	for(int ty=0;ty<2;ty++)
		for(int i=0;i<=c0;i++)
			f[0][ty][i][0]=0;
	f[0][0][0][0]=1;
	int mxx=0;
	int now=0,lst=1;
	for(int i=1;i<=tp1;i++){
		now^=1,lst^=1;
		int Num=p1[i].num,oo=p1[i].dis,Dif=rev[i],lv=mxx;
		mxx+=Num;
		for(int ty=0;ty<2;ty++)
			for(int i=0;i<=c0;i++)
				for(int j=0;j<=mxx;j++)
					f[now][ty][i][j]=0;
		for(int ty=0;ty<2;ty++){
			int mus=-1;
			if(i>1&&p1[i].bel==p1[i-1].bel)mus=ty;
			for(int i=c0;i>=0;--i)
				for(int j=mxx;j>=0;--j){
					if(mus!=1){
						if(oo!=0&&i>=Dif&&j>=Num&&j-Num<=lv)Add(f[now][0][i][j],f[lst][ty][i-Dif][j-Num]);
						if(oo!=1&&i>=Dif&&j<=lv)Add(f[now][0][i][j],f[lst][ty][i-Dif][j]);
					}
					if(mus!=0){
						if(oo!=2&&j>=Num&&j-Num<=lv)Add(f[now][1][i][j],f[lst][ty][i][j-Num]);
						if(oo!=3&&j<=lv)Add(f[now][1][i][j],f[lst][ty][i][j]);
					}
			}
		}
	}
	int als=0;
	for(int ty=0;ty<2;ty++)
		for(int i=0;i<=c0;i++)
			for(int j=0;j<=mxx;j++){
				int val=f[now][ty][i][j];
				if(!val)continue;
				int cl=max(0,sum-c1-i),cr=c0-i;
				int nl=max(0,sum-d1-j),nr=d0-j;
				Add(als,mul(val,mul(GG(cl,cr),GF(nl,nr))));
			}
	printf("%d\n",als);
}
int main()
{
	int t;
	for(scanf("%d",&t);t;--t)
		solve();
	return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM