BZOJ 1283: 序列
Description
在长度为 \(n\)的序列中选出一个子序列,满足任意长度为 \(m\) 的子串中出现的数字不超过 \(k\) 个,求最大价值 \(n \leqslant 10^3, m,k\leqslant 10^2\).
Solution
费用流.
费用流建模的一个思路,任意 \(m\) 长序列满足条件,那么就让一个点往他后面的第\(m\)个点连边,容量为\(1\),费用为这个点的权值,从源点再连出来一条容量为\(k\)的边即可,中间所有相邻的先全部连容量无穷没有费用的边,让图连通,并且这些边不可能而被割掉.
还有一种思路是从线性规划来建.
我们可以列出一堆式子来,通过添加辅助变量$y_i$
\(a_1+a_2+...+a_m+y_1=k\)
\(a_2+a_3+...+a_{m+1}+y_2=k\)
\(...\)
\(a_{n-m+1}+a_{n-m+2}+...a_n+y_{n-m+1}=k\)
然后用下面的式子去减上面的式子
\(a_1+a_2+...+a_m+y_1=k\)
\(a_{m+1}+y_2=a_1+y_1\)
\(...\)
\(a_{n-m}+y_{n-m+1}=a_n+y_n\)
\(a_{n-m+1}+...+a_n+y_{n-m+1}=k\)
然后将等式看做节点,等式两边分别表示入流和出流,变量看做是边的流量,建出来的图是一样的.
Code
/************************************************************** Problem: 1283 User: BeiYu Language: C++ Result: Accepted Time:320 ms Memory:1512 kb ****************************************************************/ #include <bits/stdc++.h> using namespace std; #define debug(a) cout<<#a<<"="<<a<<" " const int N = 2005; const int INF = 0x3fffffff; inline int in(int x=0) { scanf("%d",&x);return x; } int n,m,k; int w[N]; struct Network { int e; struct Edge { int fr,to,fl,w; }edge[N*5]; vector< int > g[N]; int a[N],p[N],b[N],d[N]; int s,t,flow,cost; void AddEdge(int fr,int to,int fl,int w) { g[fr].push_back(e); edge[e++]=(Edge){ fr,to,fl,w }; g[to].push_back(e); edge[e++]=(Edge){ to,fr,0,-w }; } int SPFA(int s,int t) { queue< int > q;q.push(s); memset(b,0,sizeof(b)),memset(d,0x80,sizeof(d)); a[s]=INF,d[s]=0; for(int x;!q.empty();) { x=q.front(),q.pop(),b[x]=0; // debug(x)<<endl; for(int i=0,v;i<(int)g[x].size();i++) if(edge[g[x][i]].fl>0 && d[x]+edge[g[x][i]].w>d[v=edge[g[x][i]].to]) { d[v]=d[x]+edge[g[x][i]].w,p[v]=g[x][i],a[v]=min(a[x],edge[g[x][i]].fl); // debug(d[v]),debug(a[v])<<endl; if(!b[v]) q.push(v),b[v]=1; } } if(d[t]<0) return 0; // debug(d[t])<<endl; cost+=a[t]*d[t],flow+=a[t]; for(int x=t;x!=s;x=edge[p[x]].fr) { edge[p[x]].fl-=a[t]; edge[p[x]^1].fl+=a[t]; } return 1; } void Build() { s=0,t=n+1; AddEdge(s,1,k,0),AddEdge(n,t,INF,0); for(int i=1;i<=n;i++) { if(i!=n) AddEdge(i,i+1,INF,0); if(i+m<=n) AddEdge(i,i+m,1,w[i]); else AddEdge(i,t,1,w[i]); } } void Work() { Build(); while(SPFA(s,t)); printf("%d\n",cost); } }py; int main() { n=in(),m=in(),k=in(); for(int i=1;i<=n;i++) w[i]=in(); py.Work(); return 0; } /* 10 5 3 4 4 4 6 6 6 6 6 4 4 */