cf 1208E

Posted nuchenghao

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了cf 1208E相关的知识,希望对你有一定的参考价值。

给定n个序列,每个一行,每个序列是可以左右移动的,对于每行可以随意移动的情况下,求每列的和的最大值

n行(1<=n<=10^6) ,w列(1<=w<=10^6)

题解:

首先由于左右边界的限制,最大为w,所以对于每行,可以填进一个列中的数是被限制的。所以我们要找到在这些可选的数中的最大值。因为这些可选的数都是连续的,并且要找最大值,可以想到用ST表查找区间最大值。

对于每个序列分成两种情况:

1.序列长度小于w的一半,这种情况是有某些处于中间的列可以选择所有输入序列的数,开头/结尾的k个直接维护前k个的最大值。影响进行差分处理。

2.长度大于等于w的一半,直接st表求出最大值即可,使用差分维护。

#include <bits/stdc++.h>
using namespace std;
#define  ll long long
int n,w,m,lg[1000100],st[2000100][23];
ll ans[1000100];
inline int query(int l,int r)

    int k=lg[r-l+1];
    return max(st[l][k],st[r-(1<<k)+1][k]);

int main()

    int i,j,k;
    scanf("%d%d",&n,&w);
    for(i=2;i<=1000000;i++)lg[i]=lg[i>>1]+1;
    for(int kk=1;kk<=n;kk++)
    
        scanf("%d",&m);
        for(i=1;i<=m;i++)scanf("%d",&st[i][0]);
        for(i=1;i<=20;i++)
            for(j=1;j<=m;j++)
                st[j][i]=max(st[j][i-1],st[j+(1<<(i-1))][i-1]);
         if(2*m>=w)//第二种情况
         
             for(i=1;i<=w;i++)
             
                 int l=m-w+i,r=i,v=query(max(l,1),min(r,m));
                 if(l<1||r>m)v=max(v,0);//可以有不选的情况(即靠近端点处的特殊情况)
                 ans[i]+=(ll)v;
                 ans[i+1]-=(ll)v;
             
          else 
             int v1 = 0, v2 = 0;
             for (i = 1; i <= m; i++)
             
                 v1 = max(v1, st[i][0]);
                 v2 = max(v2, st[m - i + 1][0]);
                 ans[i] += (ll) v1;
                 ans[i + 1] -= (ll) v1;
                 ans[w - i + 1] += (ll) v2;
                 ans[w - i + 2] -= (ll) v2;
             
             ans[m + 1] += (ll) v1;
             ans[w - m + 1] -= (ll) v1;
         
    
    for(i=1;i<=w;i++)
    
        ans[i]+=ans[i-1];
        printf("%lld ",ans[i]);
    
    puts("");
    return 0;

以上是关于cf 1208E的主要内容,如果未能解决你的问题,请参考以下文章

1208E Let Them Slide

关于安排

CF 爆发者

[CF930E]/[CF944G]Coins Exhibition

CF怎么改名

dp专题