• 【BZOJ3502/2288】PA2012 Tanie linie/【POJ Challenge】生日礼物 堆+链表(模拟费用流)


    【BZOJ3502】PA2012 Tanie linie

    Description

     n个数字,求不相交的总和最大的最多k个连续子序列。
     1<= k<= N<= 1000000。

    Sample Input

    5 2
    7 -3 4 -9 5

    Sample Output

    13

    题解:跟1150和2151差不多。

    我们先做一些预处理,因为连续的正数和连续的负数一定是要么都选要么都不选,所以可以将它们合并成一个数,同时区间中的零以及左右两端的负数没有意义,可以将它们删掉。然后我们得到的序列就变成:正-负-正-...-负-正。

    然后我们贪心的把所有正数都选了,如果正数的部分<=k,那么直接取光即可,否则,我们还要将我们的子串个数减少一些。如何减少呢?1:将某个正数由选变为不选。2.将某个负数由不选变为选。我们发现,这两种情况都会使答案减少:那个数的绝对值,所以我们可以用堆维护所有数的绝对值,然后每次都贪心的选取绝对值小的。

    但是直接贪心肯定不行,我们要模拟费用流的过程,也就是加入一个反悔操作。发现:如果对一个整数进行了1操作,那么我们就无法对它相邻的负数进行2操作;如果对一个负数进行了2操作,那么我们就无法对它相邻的正数进行1操作。所以我们再堆中删掉与它相邻的点。那么怎么反悔呢?如果当前是b,b的前驱是a,后继是c,那么向堆中加入a+c-b。如果再次选择了a+c-b,意味着我们撤销了对b的操作,而是对a和c进行操作,这样就和费用流是一样的了。

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    #include <utility>
    #include <algorithm>
    #define mp(A,B) make_pair(A,B)
    using namespace std;
    typedef long long ll;
    const int maxn=1000010;
    int n,m,k;
    ll ans;
    ll v[maxn],p[maxn];
    int pre[maxn],nxt[maxn],del[maxn];
    typedef pair<ll,int> pli;
    priority_queue<pli> q;
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    int main()
    {
    	n=rd(),m=rd();
    	int i,a,b,tp=0;
    	for(i=1;i<=n;i++)
    	{
    		v[i]=rd();
    		if(v[i]>0)
    		{
    			ans+=v[i];
    			if(p[tp]>0)	p[tp]+=v[i];
    			else	p[++tp]=v[i];
    		}
    		if(v[i]<0)
    		{
    			if(p[tp]<=0)	p[tp]+=v[i];
    			else	p[++tp]=v[i];
    		}
    	}
    	if(p[tp]<=0)	tp--;
    	n=tp;
    	if((n+1)>>1<=m)
    	{
    		printf("%lld
    ",ans);
    		return 0;
    	}
    	m=((n+1)>>1)-m;
    	for(i=1;i<=n;i++)	p[i]=abs(p[i]),q.push(mp(-p[i],i)),pre[i]=i-1,nxt[i]=(i<n)?(i+1):0;
    	while(m--)
    	{
    		while(del[q.top().second])	q.pop();
    		ans+=q.top().first,i=q.top().second,q.pop();
    		a=pre[i],b=nxt[i],del[a]=del[b]=1;
    		if(a&&b)
    		{
    			pre[i]=pre[a],nxt[i]=nxt[b];
    			if(pre[i])	nxt[pre[i]]=i;
    			if(nxt[i])	pre[nxt[i]]=i;
    			p[i]=p[a]+p[b]-p[i],q.push(mp(-p[i],i));
    		}
    		else
    		{
    			pre[i]=pre[a],nxt[i]=nxt[b];
    			if(pre[i])	nxt[pre[i]]=nxt[i];
    			if(nxt[i])	pre[nxt[i]]=pre[i];
    			del[i]=1;
    		}
    	}
    	printf("%lld",ans);
    	return 0;
    }
  • 相关阅读:
    21班考试总结
    性别
    2019.08.20上课笔记2
    2019.08.20上课笔记3
    2019.08.20上课笔记1
    单词2
    数据类和运算符
    2019.08.14单词1
    2019.08.14上课笔记1
    request.get... getHeader 能取得的信息 参数
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7560491.html
Copyright © 2020-2023  润新知