bzoj 1283: 序列
1283: 序列
Time Limit: 10 Sec Memory Limit: 162 MBSubmit: 486 Solved: 280
[Submit][Status][Discuss]
Description
给出一个长度为 的正整数序列Ci,求一个子序列,使得原序列中任意长度为M的子串中被选出的元素不超过K(K,M<=100) 个,并且选出的元素之和最大。
Input
第1行三个数N,m,k。 接下来N行,每行一个字符串表示Ci。
Output
最大和。
Sample Input
10 5 3
4 4 4 6 6 6 6 6 4 4
4 4 4 6 6 6 6 6 4 4
Sample Output
30
HINT
20%的数据:n<=10。
100%的数据:N<=1000,k,m<=100。Ci<=20000。
一个非常经典的网络流问题,题目要求的 每个相邻的k个数中不能选超过M个相当于 从n个数中选k次,且每次选的数两两直接距离>M。
然后我们就 从 i -> i+1 容量 inf 费用 0,表示不选; 从i -> min(i+M,T) 容量 1 费用 0,表示某一轮选这个数;再连 S->1 容量 k 费用 0.
这样最大费用最大流就是答案了。
#include<bits/stdc++.h> #define ll long long #define pb push_back using namespace std; const int maxn=1005; const int inf=1e9; vector<int> g[maxn]; struct lines{ int from,to,flow,cap,cost; }l[maxn*200]; int S,T,t=-1,A[maxn],d[maxn]; int n,m,k,a[maxn],ans,p[maxn]; bool iq[maxn]; inline void add(int from,int to,int cap,int cost){ l[++t]=(lines){from,to,0,cap,cost},g[from].pb(t); l[++t]=(lines){to,from,0,0,-cost},g[to].pb(t); } inline bool SPFA(){ memset(d,-0x3f,sizeof(d)); queue<int> q; q.push(S),d[S]=0,iq[S]=1,p[S]=0,A[S]=inf; int x; lines e; while(!q.empty()){ x=q.front(),q.pop(); for(int i=g[x].size()-1;i>=0;i--){ e=l[g[x][i]]; if(e.flow<e.cap&&d[x]+e.cost>d[e.to]){ d[e.to]=d[x]+e.cost; A[e.to]=min(A[x],e.cap-e.flow); p[e.to]=g[x][i]; if(!iq[e.to]) iq[e.to]=1,q.push(e.to); } } iq[x]=0; } if(d[T]==d[T+1]) return 0; ans+=d[T]*A[T]; int now=T,pre; while(now!=S){ pre=p[now]; l[pre].flow+=A[T]; l[pre^1].flow-=A[T]; now=l[pre].from; } return 1; } inline void MFMC(){ while(SPFA()); } int main(){ scanf("%d%d%d",&n,&m,&k),S=0,T=n+1; for(int i=1;i<=n;i++) scanf("%d",a+i); add(S,1,k,0); for(int i=1;i<=n;i++) add(i,i+1,inf,0),add(i,min(i+m,T),1,a[i]); MFMC(),printf("%d\n",ans); return 0; }
我爱学习,学习使我快乐