P r o b l e m \mathrm{Problem} Problem
S o l u t i o n \mathrm{Solution} Solution
可以想到,当任意两个人权值不同时,一定是w值大的匹配w值小的。
当 w w w值相同时,则有 p = 1 p=1 p=1时匹配 p = 2 p=2 p=2或 3 3 3, p = 3 p=3 p=3匹配 3 3 3和 2 2 2.因此我们当 p = 2 p=2 p=2时赋值为 p = 4 p=4 p=4,那么就有 p p p小的为组长, p p p大的为组员。我们就按照 p p p和 w w w进行排序即可。
这样排序以后就有后面的当组长,前面的当组员。
我们设 f [ i ] [ j ] [ k ] f[i][j][k] f[i][j][k]表示前 i i i个人,有 j j j个组完成了匹配,还有 k k k个人当组员且没有找到组长。
当前
p
=
1
p=1
p=1或
3
3
3时,有:
f
[
i
]
[
j
]
[
k
]
=
f
[
i
−
1
]
[
j
−
1
]
[
k
+
1
]
+
s
[
i
]
f[i][j][k]=f[i-1][j-1][k+1]+s[i]
f[i][j][k]=f[i−1][j−1][k+1]+s[i]
表示新建了一个组。
当
p
=
3
p=3
p=3或
p
=
4
p=4
p=4时,有:
f
[
i
]
[
j
]
[
k
]
=
f
[
i
−
1
]
[
j
]
[
k
+
1
]
+
s
[
i
]
f[i][j][k]=f[i-1][j][k+1]+s[i]
f[i][j][k]=f[i−1][j][k+1]+s[i]
表示新增了一个组员.
我们发现时间复杂度为 O ( n k 2 ) O(nk^2) O(nk2).
有解就需要满足 2 k ≤ n 2k\le n 2k≤n,有因为 n k ≤ 1 0 5 nk\le 10^5 nk≤105,所以时间复杂度最大为 O ( 1 0 5 × k ) O(10^5\times k) O(105×k),大约为: O ( 1 0 5 1 0 5 ) O(10^5\sqrt {10^5}) O(105105)
#include <cstdio>
#include <iostream>
#include <algorithm>
#define int long long
using namespace std;
const int N = 3000;
int n, K;
struct node {
int w, s, p;
friend bool operator < (node p1,node p2) {
if (p1.w == p2.w) return p1.p > p2.p;
return p1.w < p2.w;
}
} a[N];
int f[2][N][N];
int read(void)
{
int s = 0, w = 0; char c = getchar();
while (c < '0' || c > '9') w |= c == '-', c = getchar();
while (c >= '0' && c <= '9') s = s*10+c-48, c = getchar();
return w ? -s : s;
}
signed main(void)
{
n = read(), K = read();
if (K * 2 > n) return puts("-1"), 0;
for (int i=1,t;i<=n;++i)
{
a[i].w = read(), a[i].s = read();
a[i].p = read();
if (a[i].p == 2) a[i].p = 4;
}
sort(a+1,a+n+1);
for (int i=0;i<N;++i)
for (int j=0;j<N;++j)
f[0][i][j] = f[1][i][j] = 1e17;
f[0][0][0] = 0;
int ans = 1e17;
for (int t=1;t<=n;++t)
{
int i = t & 1;
for (int j=0;j<=min(K,t/2);++j)
for (int k=0;k<=min(t-j*2,K);++k)
{
f[i][j][k] = f[i^1][j][k];//不选
if ((a[t].p == 3 || a[t].p == 4) && k) f[i][j][k] = min(f[i][j][k],f[i^1][j][k-1]+a[t].s);//当组员
if ((a[t].p == 1 || a[t].p == 3) && j) f[i][j][k] = min(f[i][j][k],f[i^1][j-1][k+1]+a[t].s);//组长
}
}
if (f[n&1][K][0] == 1e17) cout<<-1<<endl;
else cout<<f[n&1][K][0]<<endl;
return 0;
}