zoukankan      html  css  js  c++  java
  • 「十二省联考 2019」皮配

    「十二省联考 2019」皮配

    传送门

    Loj

    题解

    这个题目其实很妙,真的.

    首先考虑一个最简单的(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
    ",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;
    }
    
  • 相关阅读:
    大数据笔记
    关于服务器编程的笔记
    [转] IPC之管道、FIFO、socketpair
    一些公司链接
    Delphi 通过字符串实例化类
    Delphi根据字符串实例化对象
    Class-reference types 类引用类型--快要失传的技术
    GETCLASS与REGISTERCLASS的应用一例
    Delphi XE增强的RTTI妙用--动态创建包中的窗口类
    Delphi2010的RTTI增强
  • 原文地址:https://www.cnblogs.com/fexuile/p/12845667.html
Copyright © 2011-2022 走看看