题解 Emiya 家今天的饭

题目链接

题目比较长,读题的时间会长一些

除去它颇有趣味的背景

在一个矩阵中选数,每行最多只能选一个,可以不选,

每列选择的数最多不能超过所选数字个数的一半,即向下取整,可以不选,

最终选数个数不能为零,求总方案数

值得注意的是,矩阵中的每个数字的值,也意味着不同的选择

也就是说,如果这个数为2,就指单选这个数,就有两种选择,对总方案数是乘法的贡献

显然,这是一个动态规划

比起行的要求,更难实现的是列的要求

正难则反,记录不满足列的要求的方案数

显然,如果一个方案数不满足列的要求,那么有且仅有一个列不满足列的要求

因为只能有一个列选择的数超过了所选数字的一半

则一定满足,这一列选择的数,大于其他列选择的数的和

动态规划的两个维度出来了

最后,再加一个维度记录行的序列数就可以了

这是一个容斥的想法,那么总方案数就是一个很容易的dp

g[i][j],表示前i行,选了j个数的方案数

    g[0][0]=1;//什么都不选,方案数为1
	
	for(ri i=1; i<=n; ++i)
		for(ri j=0; j<=n; ++j) {
			g[i][j]=g[i-1][j];//第i行第j列不选的方案数
			if(j!=0) 
                g[i][j]=(g[i][j]+g[i-1][j-1]*s[i]%mo)%mo;
            //加上第i行第j列选的方案数
     }

不合法方案数,也是一个dp,注意:以差值优化

f[i][j],表示前i行,选数最多的那一列,比其它列选数总和多的值


	for(ri k=1; k<=m; ++k) {
        //枚举选数最多列的序列数
		memset(f,0,sizeof(f));
		f[0][n]=1;
        //理性理解,特殊判断
        //毕竟f[0][n]也是一种不合法方案
		for(ri i=1; i<=n; ++i)
			for(ri j=n-i; j<=n+i; ++j)
				f[i][j]=(f[i-1][j]+
                //没选第i行的数
                    f[i-1][j-1]*a[i][k]%mo+
                //选第i行的数,且选择a[i][k]的数
                    f[i-1][j+1]*(s[i]-a[i][k]+mo)%mo)%mo;
                //选第i行的数,且不选a[i][k]的数
		for(ri i=1; i<=n; ++i) sum1=(sum1+f[n][n+i])%mo;
       //记录不合法方案数
     }

最终,时间复杂度 O(m*n^2)

另外友情提醒,数组随用随开,开得过大会TLE

或许因为这题卡时间线


over

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值