ABC-375-E-3 Team Division · znzryb
## 题目大意
给定 $n$ 个人,每个人有一个所属组别 $team_i \in \{1,2,3\}$ 和一个权重 $s_i$。需要把所有人重新分到 3 组,使得每组权重和都等于总和的 $1/3$,并且最少改变人数(把一个人从原组分到别组算一次改变)。输出最少改变数;若无法平分则输出 $-1$。
## AC代码
具体思路见此视频
【AtCoder 初学者竞赛 375比赛讲解】 【精准空降到 1:09:56】 [https://www.bilibili.com/video/BV1UR26YnEpX/?share_source=copy_web&vd_source=6ca0bc05e7d6f39b07c1afd464edae37&t=4196](https://www.bilibili.com/video/BV1UR26YnEpX/?share_source=copy_web&vd_source=6ca0bc05e7d6f39b07c1afd464edae37&t=4196)
```cpp
// E - 3 Team Division
#include <iostream>
#include <cstring>
using namespace std;
typedef long long ll;
const ll N=110;
ll n,team[N],s[N],sum[4],S,object,dp[N][510][510],prefixSum[N];
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>n;
for(int i=1;i<=n;i++) {
cin>>team[i]>>s[i];
S+=s[i];
}
memset(dp,0x3f,sizeof(dp));
register ll inf=dp[0][0][0];
dp[0][0][0]=0;
if(S%3!=0) {
cout<<-1<<endl;
return 0;
}
for(int i=1;i<=n;i++) { // 就是算一个前缀和
prefixSum[i]=prefixSum[i-1]+s[i];
}
object=S/3;
for(int i=1;i<=n;++i) {
for(int a=0;a<=object;++a) {
for(int b=0;b<=object;++b) {
register ll res=inf;
if(s[i]<=a)
res=min(res,dp[i-1][a-s[i]][b]+(team[i] != 1));
if(s[i]<=b)
res=min(res,dp[i-1][a][b-s[i]]+(team[i] != 2));
if(s[i]<=prefixSum[i]-a-b)
res=min(res,dp[i-1][a][b]+(team[i] != 3));
dp[i][a][b]=res;
}
}
}
ll ans= dp[n][object][object]==inf ? -1:dp[n][object][object];
cout<<ans<<endl;
return 0;
}
// AC https://atcoder.jp/contests/abc375/submissions/59007037
```
## 心路历程(WA,TLE,MLE……)