BZOJ 5424: 烧桥计划

BZOJ 5424: 烧桥计划

目前暂居rk1QAQ

首先,设\(f[i][k]\)为前i个点中,选了第i个点,总共选了k个点的答案。那么就有:

\[f[i][k]=min_{j<i}\{f[j][k-1]+calc(j,i)\}+k*a[i]\]

其中,\(calc(j,i)=[s[i-1]-s[j]>m]*(s[i-1]-s[j])\)

那么转移的时候,大于m的很显然的可以用前缀和,而小于等于m的可以用单调队列处理。这样转移复杂度就变成了\(O(n^2)\)

\(1000 \le a_i\le 2000\),那么就设选的最小的k个点,k个点的贡献就是\(\frac{k*(k-1)}{2}1000\),而如果一个点也不选,那么贡献最大是\(2000n\),可以发现,当\(k\ge \sqrt{n}\)的时候,选一定不会更优了,所以只需要转移大约\(\sqrt n\)次就好了。

然后转移151次会WA,而转移152次就能A掉了,所以。。。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#include<cctype>
#define qmin(x,y) (x=min(x,y))
#define qmax(x,y) (x=max(x,y))
#define vi vector<int>
#define vit vector<int>::iterator
#define pir pair<int,int>
#define fr first
#define sc second
#define mp(x,y) make_pair(x,y)
#define rsort(x,y) (sort(x,y),reverse(x,y))
using namespace std;

inline char gc() {
//  static char buf[100000],*p1,*p2;
//  return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    return getchar();
}

template<class T>
int read(T &ans) {
    ans=0;char ch=gc();T f=1;
    while(!isdigit(ch)) {
        if(ch==EOF) return -1;
        if(ch=='-') f=-1;
        ch=gc();
    }
    while(isdigit(ch))
        ans=ans*10+ch-'0',ch=gc();
    ans*=f;return 1;
}

template<class T1,class T2>
int read(T1 &a,T2 &b) {
    return read(a)!=EOF&&read(b)!=EOF?2:EOF;
}

template<class T1,class T2,class T3>
int read(T1 &a,T2 &b,T3 &c) {
    return read(a,b)!=EOF&&read(c)!=EOF?3:EOF;
}

typedef long long ll;
const int Maxn=110000;
const int inf=0x3f3f3f3f;

int n,m,a[Maxn],s[Maxn],f[Maxn],l,r,cur,g[Maxn];
pir p[Maxn];

void push(int x,int y) {
    pir now=mp(x,y);
    while(r>=l&&p[r]>now) r--;
    p[++r]=now;
}

int front() {
    while(p[l].sc<cur) l++;
    return p[l].fr;
}

signed main() {
//  freopen("test.in","r",stdin);
    read(n,m);
    if(m<0) m=0;
    for(int i=1;i<=n;i++)
        read(a[i]);
    n++;
    for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
    int ans=inf,cnt=1;
    memset(f,0x3f,sizeof(f));
    f[0]=0;
    for(int i=1;i<=n;i++) g[i]=s[i];
//  memset(g,0x3f,sizeof(g));
//  for(int i=1;i<=n;i++) f[i]=g[i]=inf;
    for(int i=1;i<=152;i++) {
        r=0,l=1;
        cur=0;
        push(0,0);
        int temp=inf;
        for(int i=1;i<=n;i++) {
            while(s[i-1]-s[cur]>m) qmin(temp,g[cur]-s[cur]),cur++;
            int sxz=f[i];
            f[i]=s[i-1]+temp;
            qmin(f[i],front());
            push(sxz,i);
            f[i]+=cnt*a[i];
        }
        qmin(ans,f[n]);
        memcpy(g,f,sizeof(g));
        cnt++;
    }
    printf("%d\n",ans);
    return 0;
}


猜你喜欢

转载自www.cnblogs.com/shanxieng/p/10502447.html