K Subsequence
Time Limit: 2000/2000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1992 Accepted Submission(s): 457
Problem Description
Master QWsin is dating with Sindar. And now they are in a restaurant, the restaurant has n dishes in order. For each dish, it has a delicious value ai. However, they can only order k times. QWsin and Sindar have a special ordering method, because they believe that by this way they can get maximum happiness value.
Specifically, for each order, they will choose a subsequence of dishes and in this subsequence, when i<j, the subsequence must satisfies ai≤aj. After a round, they will get the sum of the subsequence and they can't choose these dishes again.
Now, master QWsin wants to know the maximum happiness value they can get but he thinks it's too easy, so he gives the problem to you. Can you answer his question?
Input
There are multiple test cases. The first line of the input contains an integer T, indicating the number of test cases. For each test case:
First line contains two positive integers n and k which are separated by spaces.
Second line contains n positive integer a1,a2,a3...an represent the delicious value of each dish.
1≤T≤5
1≤n≤2000
1≤k≤10
1≤ai≤1e5
Output
Only an integer represent the maximum happiness value they can get.
Sample Input
1 9 2 5 3 2 1 4 2 1 4 6
Sample Output
22
Source
2019 Multi-University Training Contest 3
思路:我们可以根据题意得知,我们需要求k次不下降子序列(所有子序列中元素不重复),并使k次不下降子序列的总和最大。
我们可以考虑用费用流来做,进行k次增广,求最大费用流。下面考虑建图:
首先需要将起点分成s0,s1,并建立一条s0到s1,流量为k,费用为0的边,保证可以进行k次寻找。
然后需要将每个点分成入点和出点,并且在他们之间建立流量为1,费用为-v[i]的边,保证每个点只会被选取一次,并贡献v[i]。
然后需要将s1与每个点的入点连接,建立流量为1,费用为0的边。同理将每个点的出点与终点t连接,建立流量1,费用0的边。
之后根据题目要求,将所有i<j且v[i]<=v[j]的点之间,用流量为1,费用为0的边连接他们的出点与入点。
然后就可以利用费用流求解了。
注意:出题人卡了SPFA,需要用dij来求最长路。
AC代码:
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
using namespace std;
const int MAXN = 5e3+50;
const int INF = 0x3f3f3f3f;
typedef pair<int, int> P;
struct edge{int to, cap, cost, rev;};
int n; //顶点数
vector<edge> G[MAXN]; //图的邻接表表示
int h[MAXN]; //顶点的势
int dist[MAXN]; //最短距离
int prevv[MAXN], preve[MAXN]; //最短路中的前驱结点和对应的边
//优化输入
template <class T>
inline bool scan_d(T &ret) {
char c; int sgn;
if (c = getchar(), c == EOF) return 0;
while (c != '-' && (c<'0' || c>'9')) c = getchar();
sgn = (c == '-') ? -1 : 1;
ret = (c == '-') ? 0 : (c - '0');
while (c = getchar(), c >= '0'&&c <= '9') ret = ret * 10 + (c - '0');
ret *= sgn;
return 1;
}
//向图中增加一条从from到to容量为cap费用为cost的边
void add_edge(int from, int to, int cap, int cost){
G[from].push_back((edge){to, cap, cost, G[to].size()});
G[to].push_back((edge){from, 0, -cost, G[from].size()-1});
}
//求解从s到t流量为f的最小费用流
//如果没有流量为f的流,则返回-1
//当f为0时,是流量为f的最小费用
//当f大于0时,是最大流的最小费用
int min_cost_flow(int s, int t, int &f){
int res = 0;
fill(h, h+n+1,0); //初始化h
while(f>0){
//使用Dijstra算法更新h
priority_queue<P, vector<P>, greater<P> >que;
fill(dist, dist+n+1, INF);
dist[s] = 0;
que.push(P(0, s));
while(!que.empty()){
P p = que.top(); que.pop();
int v = p.second;
if(dist[v]<p.first) continue;
for(int i = 0; i < G[v].size(); i++){
edge &e = G[v][i];
if(e.cap > 0 && dist[e.to] > dist[v] + e.cost + h[v] - h[e.to]){
dist[e.to] = dist[v] + e.cost + h[v] - h[e.to];
prevv[e.to] = v;
preve[e.to] = i;
que.push(P(dist[e.to], e.to));
}
}
}
if(dist[t] == INF){
return res;
}
for(int v = 1; v <= n; v++) h[v] += dist[v];
int d = f;
for(int v = t; v != s; v = prevv[v]){
d = min(d, G[prevv[v]][preve[v]].cap);
}
f -= d;
res += d*h[t];
for(int v = t; v != s; v = prevv[v]){
edge &e = G[prevv[v]][preve[v]];
e.cap -= d;
G[v][e.rev].cap += d;
}
}
return res;
}
int arr[2050];
int main() {
//ios::sync_with_stdio(false);
int m, k, T;
scanf("%d", &T);
while(T--){
scanf("%d%d", &m, &k);
rep(i, 1, m){
scanf("%d", &arr[i]);
}
int s0 = 2*(m+1), s1 = 2*(m+1)+1;
int t = 1;
add_edge(s0,s1,k,0);
rep(i, 1, m){
add_edge(s1, 2*i, 1, 0);
add_edge(2*i, 2*i+1, 1, -arr[i]);
add_edge(2*i+1, t, 1, 0);
}
rep(i, 1, m){
rep(j, 1, m){
if(i < j && arr[i] <= arr[j]){
add_edge(2*i+1, 2*j, 1, 0);
}
}
}
n = 2*(m+1)+1;
int mxflow = INF;
int ans = min_cost_flow(s0, t, mxflow);
printf("%d\n", -ans);
rep(i, 1, n){
G[i].clear();
}
}
return 0;
}