CF1442D Sum

link

脑子真的不够用。。。
如果想到凸包差不多就是掉坑里了
注意到这个玩意的前缀和确实是凸的
然后发现一个性质就是在选的数组里,最多只有一个数组不会被全选
全选的部分可以 \(O(nk)\)
于是可以考虑分治,用左边的暴力转移右边全选的,右边的暴力转移左边全选的
复杂度 \(O(nklogn)\)

#include <bits/stdc++.h>

using namespace std;

# define Rep(i,a,b) for(int i=a;i<=b;i++)
# define _Rep(i,a,b) for(int i=a;i>=b;i--)
# define RepG(i,u) for(int i=head[u];~i;i=e[i].next)

const int N=3005;

typedef long long ll;
typedef double db;

# define chkmax(a,b) a=max(a,b)
# define chkmin(a,b) a=min(a,b)
# define PII pair<int,int>
# define mkp make_pair

template<typename T> void read(T &x){
    x=0;int f=1;
    char c=getchar();
    for(;!isdigit(c);c=getchar())if(c=='-')f=-1;
    for(;isdigit(c);c=getchar())x=(x<<1)+(x<<3)+c-'0';
    x*=f;
}

int n,m;
ll f[N<<2][N],g[N];
vector<ll> s[N];
int a[N];

void solve(int u,int l,int r){
    if(l==r){
        Rep(i,0,min(a[l],m))f[u][i]=s[l][i];
        return;
    }
    int mid=l+r>>1;
    int lc=u<<1,rc=u<<1|1;
    solve(lc,l,mid),solve(rc,mid+1,r);
    Rep(i,l,mid)_Rep(j,m,a[i])chkmax(f[rc][j],f[rc][j-a[i]]+s[i][a[i]]);
    Rep(i,mid+1,r)_Rep(j,m,a[i])chkmax(f[lc][j],f[lc][j-a[i]]+s[i][a[i]]);
    Rep(i,0,m)f[u][i]=max(f[lc][i],f[rc][i]);
}

int main()
{
    // freopen("testdata.in","r",stdin);
    read(n),read(m);
    Rep(i,1,n){
        read(a[i]);
        s[i].resize(a[i]+2);
        Rep(j,1,a[i])read(s[i][j]);
        s[i][0]=0;
        Rep(j,1,a[i])s[i][j]+=s[i][j-1];
    }
    // Rep(i,1,n)Rep(j,1,a[i])printf("%lld%c",s[i][j],j==a[i]?'\n':' ');
    solve(1,1,n);
    printf("%lld\n",f[1][m]);
    return 0;
}
posted @ 2022-05-02 15:36  YuukiYumesaki  阅读(30)  评论(0编辑  收藏  举报