• 「十二省联考 2019」皮配


    传送门

    Solution 

    这是一道背包计数问题,所以可以从生成函数的角度来理解。

    每个选手可选择的是阵营(0/1),以及派系(0/1)

    如果一个城市选择了第(i)阵营第(j)派系,那么相当于分别让阵营(i)和派系(j)的代价(+s_i)

    设一个没有任何限制的学校的生成函数为(1+x^{s_i}+y^{s_i}+x^{s_i}y^{s_i}),其中(x)表示阵营(1)(y)表示派系(1)

    对于一个城市的学校集合为(V),假设它没有偏好学校,它的生成函数就是

    [(1+x^{Sum_{V}})prod_{iin V} 1+y^{s_i} ]

    对于含有偏好学校的城市,如果它的无偏好学校集合为(V_1),它的生成函数是

    [(1 imes Prod_0+x^{Sum_V} imes Prod_1)prod_{iin V_1} 1+y^{s_i} ]

    (Prod_1)(Prod_0)是偏好城市的生成函数的积

    假如这个城市不加入阵营(1)派系(0),那么它在(Prod_0)的贡献是((1+y^{s_i})),对(Prod_1)的贡献是(y^{s_i})

    答案是所有城市的生成函数的积中满足(x)的次和(y)的次数在范围([Sum-C_0,C_1]),和([Sum-D_0,D_1])的项的系数

    对于没有偏好的城市分别计算前部分((1+x^{Sum_V}))和后部分(prod 1+y^{s_i})的系数

    乘上有偏好学校城市的(prod_{iin V_1} 1+y^{s_i})部分

    其中(x,y)系数分开来算,这部分的复杂度是(O(nM))

    然后我们要求出((1 imes Prod_0+x^{Sum_V} imes Prod_1))的乘积,用(f_{i,j})表示(x^iy^j)的系数

    如果暴力乘的话,每个城市先分成(Prod_0)(Prod_1)分别算贡献,再加起来

    单个学校合并是(O(M_1))的,因为只有(30)个城市,(s_ileq 10),所以(M_1=300)

    城市和城市合并是(O(nM_1))的,所以总复杂度是(O(knM_1))

    最后枚举(f_{i,j}),求出(x,y)的次数区间,前缀和求区间和,相乘计入答案即可

    ps: 算的时候要把没有学校的城市去掉,不然20分欢迎你

    Code 

    #include<bits/stdc++.h>
    #define ll long long
    #define dbg1(x) cerr<<#x<<"="<<(x)<<" "
    #define dbg2(x) cerr<<#x<<"="<<(x)<<"
    "
    #define dbg3(x) cerr<<#x<<"
    "
    #define ME(x) memset(x,0,sizeof x)
    using namespace std;
    #define reg register
    inline int read()
    {
    	int x=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    	return x*f;
    }
    const int MM=2505,MN=1005,MS=11,MK=31,P=998244353;
    int Mul(int x,int y){return (1ll*x*y)%P;}
    int Add(int x,int y){return (x+y)%P;}
    bool a[MN];
    int n,c,C0,C1,D0,D1,b[MN],s[MN],k,p[MN],x[MM],y[MM],f[MM][MK*MS],f1[MM][MK*MS],sum[MN];
    void pro(int *r,int ed,int ty,int i){for(;~i;--i)r[i]=Add(r[i]*ty,i>=ed?r[i-ed]:0);}
    int main()
    {
    	int Case=read();
    	while(Case--)
    	{
    		n=read(),c=read();C0=read(),C1=read(),D0=read(),D1=read();
    		int i,j,M=max(max(C0,C1),max(D0,D1)),Sx=0,Sy=0,ans=0,S=0;
    		ME(x);ME(y);ME(f);ME(f1);ME(sum);ME(a);
    		for(i=1;i<=n;++i) b[i]=read(),s[i]=read(),p[i]=-1,sum[b[i]]+=s[i],S+=s[i];
    		for(k=read(),i=1;i<=k;++i) j=read(),p[j]=read(),a[b[j]]=1;
    		for(x[0]=i=1,j=0;i<=c;++i)if(!a[i]&&sum[i])j=min(M,j+sum[i]),pro(x,sum[i],1,j);
    		for(i=1;i<=M;++i)x[i]=Add(x[i],x[i-1]);
    		for(y[0]=i=1,j=0;i<=n;++i)if(!~p[i])j=min(M,j+s[i]),pro(y,s[i],1,j);
    		for(i=1;i<=M;++i)y[i]=Add(y[i],y[i-1]);
    		for(f[0][0]=i=1;i<=c;++i)if(a[i])
    		{
    			reg int u,v;
    			for(u=0;u<=Sx;++u)for(v=0;v<=Sy;++v)f1[u][v]=f[u][v];
    			for(j=1;j<=n;++j)if(b[j]==i&&~p[j])
    			{
    				Sy=min(Sy+s[j],M);
    				if(p[j]<2){for(u=Sx;~u;--u)pro(f1[u],s[j],1,Sy),!p[j]?(pro(f[u],s[j],0,Sy),1):1;}
    				else{for(u=Sx;~u;--u)pro(f[u],s[j],1,Sy),(p[j]<3)?(pro(f1[u],s[j],0,Sy),1):1;}
    			}
    			Sx=min(Sx+sum[i],M);
    			for(u=Sx;~u;--u)for(v=Sy;~v;--v)f[u][v]=Add(u>=sum[i]?f1[u-sum[i]][v]:0,f[u][v]);
    		}
    		for(i=Sx;~i;--i)for(j=Sy;~j;--j)if(f[i][j])
    		{
    			int lx=max(S-C0-i,0),rx=C1-i,ly=max(S-D0-j,0),ry=D1-j;if(lx>rx||ly>ry)continue;
    			ans=Add(ans,Mul(f[i][j],Mul(Add(x[rx],P-(lx?x[lx-1]:0)),Add(y[ry],P-(ly?y[ly-1]:0)))));
    		}
    		printf("%d
    ",ans);
    	}
    	return 0;
    }
    


    Blog来自PaperCloud,未经允许,请勿转载,TKS!

  • 相关阅读:
    Documents
    gitlab 安装和配置
    git相关知识
    马俊龙ansible教程分享
    源码安装python 报错,openssl: error while loading shared libraries: libssl.so.1.1
    jumpserver 常见错误解决
    nginx 定义:响应头和请求头
    gcc入门(下)
    gcc入门(上)
    awk命令
  • 原文地址:https://www.cnblogs.com/PaperCloud/p/11296584.html
Copyright © 2020-2023  润新知