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
*/

 

posted @ 2017-01-20 20:41  北北北北屿  阅读(163)  评论(0编辑  收藏  举报