zoukankan      html  css  js  c++  java
  • CF940E Cashback(DP)

    题意:

    给定一个数C,对一个序列作切割,每一段对答案的贡献是这一段的元素之和减去这一段里最小的Len/C个数之和,Len指这一段的长度。

    询问最小答案。

    题解:

    有一个结论是,两个长度为C的序列对答案的贡献一定小于这两个序列合并起来对答案的贡献。

    有个贪心的做法就是只切长度为1和长度为C的序列。

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=2e5+100;
    ll dp[maxn];
    ll c[maxn];
    ll a[maxn];
    ll n,m;
    struct node {
        ll l,r,sum;
    }segTree[maxn<<2];
    void build (ll i,ll l,ll r) {
        segTree[i].l=l;
        segTree[i].r=r;
        if (l==r) {
            segTree[i].sum=a[l];
            return;
        }
        ll mid=(l+r)>>1;
        build(i<<1,l,mid);
        build(i<<1|1,mid+1,r);
        segTree[i].sum=min(segTree[i<<1].sum,segTree[i<<1|1].sum);
    }
    ll query (int i,int l,int r) {
        if (segTree[i].l>=l&&segTree[i].r<=r) 
            return segTree[i].sum;
        ll mid=(segTree[i].l+segTree[i].r)>>1;
        ll ans=1e9;
        if (l<=mid)
            ans=min(ans,query(i<<1,l,r));
        if (r>mid)
            ans=min(ans,query(i<<1|1,l,r));
        return ans;
    }
    int main () {
        cin>>n>>m;
        for (int i=1;i<=n;i++) dp[i]=1e18;
        for (int i=1;i<=n;i++) cin>>a[i];
        for (int i=1;i<=n;i++) c[i]=c[i-1]+a[i];
        build(1,1,n);
        for (int i=1;i<=n;i++) {
            dp[i]=min(dp[i],dp[i-1]+a[i]);
            if (i>=m)
                dp[i]=min(dp[i],dp[i-m]+c[i]-c[i-m]-query(1,i-m+1,i));
        }
        cout<<dp[n];
    }
  • 相关阅读:
    Linux下的邮件发送
    Linux下用户和raid练习题
    Linux centos7.5操作系统的安装
    Linux chattr文件锁
    Linux系统下root密码丢失解决方案
    周总结2
    课堂作业1
    开课博客
    阅读3
    作业8
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/13641883.html
Copyright © 2011-2022 走看看