题解:P6403 [COCI2014-2015#2] STUDENTSKO
题面
[COCI2014-2015#2] STUDENTSKO
题目描述
一年一度的萨格勒布大学学生乒乓球团体赛将于下周六举行!每队由 \(k\) 名学生组成。\(n\) 个兴奋的学生们正在排队等候登记。Krešo 在登记处工作。他真的不想做他的工作,所以他决定不让学生选择团队。他决定第一组将由第一个排队的 \(k\) 名学生组成,第二组由下面的 \(k\) 名学生组成,第三组由后面的 \(k\) 名学生组成,以此类推。(\(n\equiv 0\pmod k\),因此没有人剩余。)
Ante 用一个整数来估计每个玩家的技能。他希望第一队拥有最弱的 \(k\) 个球员,第二队拥有第二弱的 \(k\) 个球员,依此类推,最后一队拥有最强的 \(k\) 个球员。
Krešo 刚刚休息了一下,Ante 决定转移排队的学生以达到自己的目标。他转移学生的方式是告诉一个学生从队列中走出来,在另一个学生后面排队,或者走到队列的前面。每转移一个学生花费一分钟。Krešo 有可能随时从休息中回来,所以 Ante 需要尽快实现他的目标。帮助 Ante 确定实现目标所需的最少分钟数。
输入格式
第一行输入包含整数 \(n\) 和 \(k\),满足 \(n\bmod k=0\)。
第二行包含 \(n\) 个空格分隔的整数 \(v_i\),表示第 \(i\) 个站在队列中的玩家技能的水平。
所有参赛者都有不同水平的技能。
输出格式
仅一行,即转移学生所用的最短分钟数。
样例 #1
样例输入 #1
4 1
9 12 5 13
样例输出 #1
1
样例 #2
样例输入 #2
6 2
16 2 1 7 5 10
样例输出 #2
1
样例 #3
样例输入 #3
6 3
7 9 8 3 6 5
样例输出 #3
3
提示
样例 3 说明
Ante 应该将技能等级为 \(5,6\) 和 \(3\) 的学生移到队列的前面,花了三分钟。
数据范围与约定
- 对于 \(30\%\) 的数据,有 \(1\le n\le 20\)。
- 对于 \(100\%\) 的数据,有 \(1\le n\le k\le 5\times 10^3\)。
对于所有合法的 \(v_i\),都有 \(1\le v_i\le 10^9\)。
说明
题目译自 COCI2014-2015 CONTEST #2 T3 STUDENTSKO。
题解
思路
- 因为 Ante 希望第一队拥有最弱的 \(k\) 个球员,第二队拥有第二弱的 \(k\) 个球员,依此类推,最后一队拥有最强的 \(k\) 个球员。所以应先将球员按能力从小到大排序。
- 此时球员的顺序是最理想的状态,将球员排序后,打上球队的标记,并还原球员的顺序。
- 因为原来的顺序不一定是最理想的顺序,所以要让移动次数最小,符合队伍排序的顺序最长。而这个符合队伍排序的顺序就是队伍编号的最长不降子序列。
代码
蒟蒻还不会 $O\left ( n\log_{2}{n} \right ) $,只会 $O\left ( n^2 \right ) $。
#include<bits/stdc++.h>
#define int long long
using namespace std;
struct stu {
int a, id, team;
} s[5005];
int n, k;
bool cmp1(stu A, stu B) {
return A.a < B.a;
}
bool cmp2(stu A, stu B) {
return A.id < B.id;
}
int f() {//最长不降子序列,即符合队伍排序的顺序
int dp[5005], ans = -1e9;
for (int i = 1; i <= n; i++) {
dp[i] = 1;
for (int j = 1; j < i; j++)
if (s[i].team >= s[j].team)
dp[i] = max(dp[i], dp[j] + 1);
}
for (int i = 1; i <= n; i++) ans = max(ans, dp[i]);
return ans;
}
signed main() {
cin.tie(0), cout.tie(0);
cin >> n >> k;
for (int i = 1; i <= n; i++) cin >> s[i].a;//输入
for (int i = 1; i <= n; i++) s[i].id = i;//编号,为后面还原做标记
sort(s + 1, s + 1 + n, cmp1);//按能力排序
for (int i = 1; i <= n; i++) s[i].team = (i + k - 1) / k;//打上队伍标号
sort(s + 1, s + 1 + n, cmp2);//还原
cout << n - f()<<"\n";
return 0;
}

浙公网安备 33010602011771号