• BZOJ 1283: 序列


    1283: 序列

    Time Limit: 10 Sec  Memory Limit: 162 MB
    Submit: 327  Solved: 185
    [Submit][Status][Discuss]

    Description

    给出一个长度为 的正整数序列Ci,求一个子序列,使得原序列中任意长度为 的子串中被选出的元素不超过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

    Sample Output

    30

    HINT

    20%的数据:n<=10。
    100%的数据:N<=1000,k,m<=100。Ci<=20000。

    Source

    分析:

    和NOI2008志愿者招募很像...有一些区间限制然后求最大(小)费用...

    我们可以把所有长度为$m$的子串中选择$k$个元素看成在所有长度为$m$的子串中选$k$次,那么我们连一串$<i-1,i,k,0>$的边来保证每个点最多被选择$k$次,然后连一些$<i,i+m,1,a[i]>$的边来表示当前的点选了之后这个流只能在$i+m$之后的位置再去选择,也就保证了当前子串当前次只选了一个元素,然后跑最大费用最大流就好....

    代码:

    #include<algorithm>
    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<queue>
    //by NeighThorn
    #define inf 0x3f3f3f3f
    using namespace std;
    
    const int maxn=1000+5,maxm=maxn*5;
    
    int n,m,k,S,T,cnt,a[maxn],w[maxm],hd[maxn],to[maxm],fl[maxm],nxt[maxm],vis[maxn],dis[maxn],Min[maxn],from[maxn];
    
    inline void add(int x,int y,int s,int l){
    	w[cnt]= l,fl[cnt]=s,to[cnt]=y,nxt[cnt]=hd[x],hd[x]=cnt++;
    	w[cnt]=-l,fl[cnt]=0,to[cnt]=x,nxt[cnt]=hd[y],hd[y]=cnt++;
    }
    
    inline bool spfa(void){
    	memset(dis,inf,sizeof(dis));
    	memset(Min,inf,sizeof(Min));
    	queue<int> q;q.push(S),vis[S]=1,dis[S]=0;
    	while(!q.empty()){
    		int top=q.front();q.pop();vis[top]=0;
    		for(int i=hd[top];i!=-1;i=nxt[i])
    			if(dis[to[i]]>dis[top]+w[i]&&fl[i]){
    				from[to[i]]=i;
    				dis[to[i]]=dis[top]+w[i];
    				Min[to[i]]=min(fl[i],Min[top]);
    				if(!vis[to[i]])
    					q.push(to[i]),vis[to[i]]=1;
    			}
    	}
    	return dis[T]!=inf;
    }
    
    inline int find(void){
    	for(int i=T;i!=S;i=to[from[i]^1])
    		fl[from[i]]-=Min[T],fl[from[i]^1]+=Min[T];
    	return Min[T]*dis[T];
    }
    
    inline int mcmf(void){
    	int res=0;
    	while(spfa())
    		res+=find();
    	return res;
    }
    
    signed main(void){
    #ifndef ONLINE_JUDGE
    	freopen("in.txt","r",stdin);
    #endif
    	memset(hd,-1,sizeof(hd));
    	scanf("%d%d%d",&n,&m,&k);
    	S=0;T=n+1;add(S,1,k,0);
    	for(int i=1;i<=n;i++)
    		scanf("%d",&a[i]),add(i,i+1,i+1==T?inf:k,0);
    	for(int i=1;i<=n;i++)
    		add(i,i+m>n?T:i+m,1,-a[i]);
    	printf("%d
    ",-mcmf());
    	return 0;
    }
    

      


    By NeighThorn

  • 相关阅读:
    for,foreach,$.each()跳出循环的比较
    十大经典排序算法
    沙箱模式以及其使用到的IIFE
    绝对路径和相对路径的区别
    必备的JS调试技巧汇总
    通过.frm表结构和.ibd文件恢复数据
    Jenkins使用QQ邮箱构建邮件提醒服务
    windows常用命令积累
    7.手机屏幕分辨率
    6.移动端App安装包的测试用例
  • 原文地址:https://www.cnblogs.com/neighthorn/p/6554421.html
Copyright © 2020-2023  润新知