luogu P5289 [十二省联考2019]皮配 背包

LINK:皮配

我承认是一道很难的题目。

不过对于这道题 部分分的提示显得尤为重要。

首先是 40分的暴力dp 很容易想 但是不容易写。

从40分可以发现我们只需要把蓝阵营和鸭派系的人数给存在起来就行了 此时可以获得50分。

观察题目中存在k==0的情况 可以发现 加入阵营和派系没有什么关系 所以就可以分开的做。

考虑100分 容易发现有毒的学校就30个 对于这三十个城市单独做暴力dp 剩下的按照上述方法。

一个难点:可以发现 学校选择的派系是影响城市的 所以感觉这样做不太行。

把有毒的城放在一起dp 很遗憾这样做复杂度最快也是(nm^2)的 过不了。

可以发现 对于那些没有毒的学校但有毒的城市来说 没有毒的学校还是可以对于派系随便选的。

对于有毒的城市选择阵营的时候一起做 选择派系的时候单独做。

这样还是只做了k个城市。

设总体的状态为f[i][j]表示前T个城市蓝阵营i人鸭派系j的方案数。

对于每个城市单独dp的话需要提前处理一个g数组 表示当前城市 前G个学校蓝阵营i人鸭派系j人的方案数。

进一步的可以发现这个状态可以变成g1[j]表示加入蓝阵营鸭派系j人 g2[j]表示加入红阵营j人的方案数。

可以发现合并的时候还要枚举一个决策k 所以总复杂度为(km^3)的。

一个trick 直接让g1和g2代替f数组 然后再进行转移 这样就不需要合并背包了。

复杂度(km^2). 没开o2速度排在rk8 常数海星. !注意边界问题。

const int MAXN=1010,maxn=2510;
int n,T,c,C0,C1,sum,D0,D1,lim1,lim2;
int sc[MAXN],wc[MAXN],f[maxn][maxn];
struct wy{int c,s;int op;}t[MAXN];
int f1[maxn],f2[maxn],g1[maxn][maxn],g2[maxn][maxn];
inline void add(int &x,int y){x=x+y>=mod?x+y-mod:x+y;}
inline int cmp(wy a,wy b){return a.c<b.c;}
inline int calc1(int s)
{
	int l=max(0,sum-s-C1),r=C0-s;
	if(l>r)return 0;
	if(!l)return f1[r];
	return (f1[r]-f1[l-1]+mod)%mod;
}
inline int calc2(int s)
{
	int l=max(0,sum-s-D1),r=D0-s;
	if(l>r)return 0;
	if(!l)return f2[r];
	return (f2[r]-f2[l-1]+mod)%mod;
}
inline void cle()
{
	rep(1,n,i)sc[i]=wc[i]=0;
	rep(0,max(C0,D0),i)f1[i]=f2[i]=0;
	rep(0,lim1,i)rep(0,lim2,j)g1[i][j]=g2[i][j]=f[i][j]=0;
	lim1=lim2=sum=0;
}
int main()
{
	freopen("1.in","r",stdin);
	get(T);
	while(T--)
	{
		get(n);get(c);
		get(C0);get(C1);get(D0);get(D1);
		rep(1,n,i)
		{
			int get(x),get(y);
			t[i]=(wy){x,y,0};
			sum+=y;wc[x]+=y;
		}
		C0=min(C0,sum);C1=min(C1,sum);
		D0=min(D0,sum);D1=min(D1,sum);
		int get(Q);
		rep(1,Q,i)
		{
			int get(x),get(y);
			op(x)=y+1;sc[c(x)]=1;
		}
		f1[0]=f2[0]=1;
		//f1对城市进行dp f2对学校进行dp.
		rep(1,c,i)
		{
			if(sc[i]||!wc[i])continue;
			fep(C0,wc[i],j)add(f1[j],f1[j-wc[i]]);
		}
		rep(1,n,i)
		{
			if(op(i))continue;
			fep(D0,s(i),j)add(f2[j],f2[j-s(i)]);
		}
		//对所有有毒的城市进行dp.
		//f[i][j]表示蓝阵营i人鸭派系j人的方案数.
		int flag=1,sum1=0,sum2=0;//分别表示进入阵营和进入派系的人数.
		sort(t+1,t+1+n,cmp);f[0][0]=1;
		rep(1,c,G)
		{
			int st=flag;
			while(c(flag)==G&&flag<=n)++flag;
			int en=flag-1;
			if(!sc[G])continue;
			rep(0,lim1,i)rep(0,lim2,j)g2[i][j]=g1[i][j]=f[i][j];
			rep(st,en,k)//只dp有毒的城市.
			{
				if(op(k))
				{
					sum2+=s(k);
					lim2=min(sum2,D0);
					fep(lim1,0,i)fep(lim2,0,j)
					{
						g1[i][j]=((j>=s(k)?g1[i][j-s(k)]*(op(k)!=1):0)+g1[i][j]*(op(k)!=2))%mod;
						g2[i][j]=((j>=s(k)?g2[i][j-s(k)]*(op(k)!=3):0)+g2[i][j]*(op(k)!=4))%mod;
					}
				}
			}
			sum1+=wc[G];
			lim1=min(sum1,C0);
			fep(lim1,0,i)fep(lim2,0,j)f[i][j]=((i>=wc[G]?g1[i-wc[G]][j]:0)+g2[i][j])%mod;
		}
		rep(1,max(C0,D0),i)add(f1[i],f1[i-1]),add(f2[i],f2[i-1]);
		int ans=0;
		rep(0,lim1,i)
		rep(0,lim2,j)
		add(ans,(ll)f[i][j]*calc1(i)%mod*calc2(j)%mod);
		put(ans);cle();
	}
	return 0;
}
原文地址:https://www.cnblogs.com/chdy/p/13127005.html