洛谷比赛 堕落的Joe

/*暴力50*/
#include<iostream>
#include<cstdio>
#include<cstring>
#define maxn 100010
#define ll long long
using namespace std;
ll n,k,f[maxn][],a[maxn],ans;
ll init(){
ll x=,f=;char s=getchar();
while(s<''||s>''){if(s=='-')f=-;s=getchar();}
while(s>=''&&s<=''){x=x*+s-'';s=getchar();}
return x*f;
}
int main()
{
n=init();k=init();
for(int i=;i<=n;i++)
a[i]=init();
for(int i=;i<=n;i++)
for(int j=;j<=k;j++){
if(j>)f[i][j]=max(f[i][j],f[i-][j-]+a[i]);
f[i][]=max(f[i][],f[i-][j]);
ans=max(ans,f[i][j]);
ans=max(ans,f[i][]);
}
printf("%lld",ans);
return ;
}
/*
暴力的算法不好优化啊QAQ
问了一下长郡中学的shenben学弟
换一个状态 f[i]表示前i个且选了第i个的最大值
n*n的做法是枚举前面的没选的最大的f[j-1]+a[j+1]+a[j+2]+...+a[i]
转移就是 f[i]=max(f[j-1]+a[j+1]+a[j+2]+...+a[i])
考虑到选j与i无关 所以只要找max f[j-1]-s[j]
这里选就选一段 只要保证了i-j<=k就好了
优化嘛 单调队列 里面自然是维护 f[j-1]-s[j] 的最大值
时效性上面说的 i-j<=k
然后 维护下前缀和
*/
#include<cstdio>
#define maxn 1000010
#define ll long long
using namespace std;
ll n,k,x,a[maxn],f[maxn],q[maxn],head,tail,ans;
ll max(ll a,ll b){
return a<b?b:a;
}
ll init(){
ll x=,f=;char s=getchar();
while(s<''||s>''){if(s=='-')f=-;s=getchar();}
while(s>=''&&s<=''){x=x*+s-'';s=getchar();}
return x*f;
}
void ins(ll x){
while(f[q[tail]-]-a[q[tail]]<f[x-]-a[x]&&head<=tail)
tail--;
q[++tail]=x;
}
int main()
{
n=init();k=init();
for(int i=;i<=n;i++){
x=init();
a[i]=x+a[i-];
}
ins();
for(int i=;i<=n;i++){
int p=q[head];
f[i]=f[p-]+a[i]-a[p];
ans=max(ans,f[i]);
if(i-q[head]==k)head++;
if(i!=n)ins(i+);
}
printf("%lld\n",ans);
return ;
}
上一篇:UVA 10954 Add All 哈夫曼编码


下一篇:数据库中的參照完整性(Foreign Key)