CF1954D Colored Balls 题解 Solution

题意简述:

无。

但是有个重点(在输入格式里):所有球的数量和小于等于 5000 5000 5000

题解:

解法一:暴力枚举每一个是否被选中,时间爆炸!

解法二(正解):

考虑 dp,我们记录一个数组 p p p,来维护当所有选取方案中球的数量总和为 s u m sum sum 时的方案数。

再考虑枚举两维,第一维枚举球 i i i,第二维枚举球的数量的总和 j j j,假设 i i i 球出现的数量为 a i a_i ai,考虑以下两种情况:

  • 如果 j ≤ a i j\le a_i jai,即原有球的总和小于等于这种球的数量,仔细思考,可以发现需要分成 a i a_i ai 组。
  • 否则,可以分成 ⌈ a i + j 2 ⌉ \lceil\frac {a_i+j}{2}\rceil 2ai+j 组(可以自己推导一下为什么)。

那么 dp 方程很好想到:

if(j+x<=M)p[j+x]=(p[j+x]+p[j])%mod;

我们只要倒序枚举(因为这是一个类似于普通背包问题的动态规划),并且统计答案就好了。

注意:

  • 记得取模;
  • 也需要开 longlong?

代码如下:

#include<bits/stdc++.h>
#define N 5010
#define M 5000
#define mod 998244353//取模
#define I_love_Furina return //发电+放抄袭
#define forever 0
#define int long long
using namespace std;
int n,ans,a[N],p[N];//如题解
signed main(){
	ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++)cin>>a[i];
	sort(a+1,a+n+1);//排序一下
	p[0]=1;//初始赋值
	for(int i=1;i<=n;i++){
		int x=a[i],fl=x%2;
		for(int j=M;j>=x+1;j--){//倒续
			ans=(((j+x)/2+(j+x)%2)*p[j]%mod+ans)%mod;//统计答案,第二情况
			if(j+x<=M)p[j+x]=(p[j+x]+p[j])%mod;//状态转移
		}
		for(int j=x;j>=0;j--){//倒序
			ans=(p[j]*x%mod+ans)%mod;//统计答案,第一情况
			if(j+x<=M)p[j+x]=(p[j+x]+p[j])%mod;//状态转移
		}
	}
	cout<<ans;
	I_love_Furina forever;//完结撒花
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值