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;
}