首页 > 其他分享 >ABC375

ABC375

时间:2024-10-17 10:35:09浏览次数:1  
标签:min int sum leq 1505 ABC375 dp

E

题目大意:

\(n\)个人,每个人初始在第\(a_i\)组,有一个力量值\(b_i\)。需要调整某些人到其他组去,使得每个组的力量值相等。若能,求出最少调整的人数。若不能,输出\(-1\)。\(n\leq 100,1\leq b_i,\sum b_i \leq 1500,a_i\in\{1,2,3\}\)。

分析:

暴力dfs显然不行,还要求最少调整的人数,只能是dp了呀!至于dp的状态,题目里面就只有\(a_i\)和\(b_i\),显然就用\(b_i\)来设状态。设\(dp[i][x][y]\)表示考虑到第\(i\)个人,前\(i-1\)个人的第一组的力量值之和为\(x\),第二组的力量值之和为\(y\)。此处特别注意:\(i\)这一维是有必要的,不可以省略!因为转移过程为:前\(i-1\)个的和分别是\(x\)和\(y\),然后考虑当前的\(i\)放在那一组后进行转移。如果没有\(i\)这一维,意味着无法体现一个一个考虑的过程了,即自己可以贡献自己,这是不行的!用滚动数组优化,复杂度\(O(n(\sum b_i) ^ 2)\)。

代码:

#include <bits/stdc++.h>

using namespace std;

int n, s[4], a[105], b[105], dp[2][1505][1505];

int main()
{
	scanf("%d", &n);
	for (int i = 1; i <= n; i ++ ) scanf("%d%d", &a[i], &b[i]), s[a[i]] += b[i], s[0] += b[i];
	if (s[0] % 3) {puts("-1"); return 0;}
	memset(dp, 0x3f, sizeof(dp)); dp[0][s[1]][s[2]] = dp[1][s[1]][s[2]] = 0;
	for (int k = 1; k <= n; k ++ )
	{
		int o = (k & 1);
		for (int i = 0; i <= 1500; i ++ )
		{
			for (int j = 0; j <= 1500; j ++ )
			{
				dp[o][i][j] = min(dp[o][i][j], dp[o ^ 1][i][j]);
				if (a[k] == 1)
				{
					if (i >= b[k] && j + b[k] <= 1500) dp[o][i - b[k]][j + b[k]] = min(dp[o][i - b[k]][j + b[k]], dp[o ^ 1][i][j] + 1);
					if (i >= b[k]) dp[o][i - b[k]][j] = min(dp[o][i - b[k]][j], dp[o ^ 1][i][j] + 1);
				}
				if (a[k] == 2)
				{
					if (i + b[k] <= 1500 && j >= b[k]) dp[o][i + b[k]][j - b[k]] = min(dp[o][i + b[k]][j - b[k]], dp[o ^ 1][i][j] + 1);
					if (j >= b[k]) dp[o][i][j - b[k]] = min(dp[o][i][j - b[k]], dp[o ^ 1][i][j] + 1);
				}
				if (a[k] == 3)
				{
					if (i + b[k] <= 1500) dp[o][i + b[k]][j] = min(dp[o][i + b[k]][j], dp[o ^ 1][i][j] + 1);
					if (j + b[k] <= 1500) dp[o][i][j + b[k]] = min(dp[o][i][j + b[k]], dp[o ^ 1][i][j] + 1);
				}
			}
		}
	}
	printf("%d\n", dp[n & 1][s[0] / 3][s[0] / 3] > n ? -1 : dp[n & 1][s[0] / 3][s[0] / 3]);
	return 0;
}

标签:min,int,sum,leq,1505,ABC375,dp
From: https://www.cnblogs.com/andysj/p/18470495

相关文章

  • ABC375 Review
    ABC375ReviewAB模拟题过C很让人恼怒的一道题,思路一点也不难想,但是代码实现过于困难了(对于我来说)分析自己找一两组样例就会发现这道题实际上实在模拟一个矩阵不断向内旋转\(90°\)的过程,从外到里旋转的次数越来越多,旋转的过程可以发现实际上可以通过模\(4\)来进行简化......
  • 24/10/13 ABC375补题笔记
    A典,属于显而易见的水题,这数据范围直接暴力做就行了。#include<bits/stdc++.h>usingnamespacestd;intmain(){ intn; cin>>n; strings; cin>>s; intcnt=0; if(n<2)returncout<<0<<endl,0; for(inti=0;i<s.size()-2;i++)......
  • ABC375 (A~G) 题解
    也是补完整场了。(虽然只有一题要补A模拟。B模拟。C模拟。D模拟。EE-3TeamDivision还想了蛮久的。题意:有三个队伍,各有一些人,人有能力值,人可以换队伍。问三个队伍能力值相同最少需要让多少人交换队伍。人数\(\le100\),值域\(\le1500\)题目还是挺误导人的,如......
  • ABC375
    前言F、G没时间写了,主要是C太唐了,甚至没想到转两遍的只需要把转一遍的循环两边就行了,浪费太多时间,D因为C++20特殊性质CE了一发,E数组开小吃了一发罚时。A、B没啥好说的从C开始吧。C-SpiralRotation发现就是从歪往里数第多少层就是顺时针转多少圈,由此\(\mod4\)......