呜呜呜,我真的太水了。
没有人说过,只要是环形的题,就要把它复制一下接在后面。然而我。。。。就犯了这米杀的错误。
这道题
关建1:分析题目的性质,找出有用的信息,即实质所要求的东西
关键2:如果按着题目的描述,来dp的话很难表示,所以通过互补的思维,另一向的思维来做
rmq的模版,以前做这个rmq跪过,最后发现是括号加错了位置!!!int后面的括号要把整个除法都扩住!!,以前没有加括号,就误以为光分子啊!!
k=(int)(log(double(r-l+1))/log(2.0)))
这道题总说:非常锻炼对题目性质与实质的分析
#include<cstdio>
#include<cstring>
#include<cmath>
#include<cstdlib>
#include<algorithm>
using namespace std;
typedef long long ll;
const ll inf=10000000000;
ll f[2005][2005][2];
ll mi[2005][20];
int n,m;
ll a[2005];
void init()
{
for (int i=1;i<=n;i++) mi[i][0]=a[i];
for (int k=1;k<=15;k++)
{
for (int i=1;i<=n;i++)
if (i+(1<<k)-1<=n)
mi[i][k]=max(mi[i][k-1],mi[i+(1<<(k-1))][k-1]);
else break;
}
}
ll MIN(int l,int r)
{
if (l>r) return 0;
//如果没这个区间的话,就返回费用为0,和下面相呼应!
//对应了取到最后,就没有费用的情况,因为问题本身,下面的+m,
//就是保证了要取数的区间,在增加的过程中,区间逐渐变小,
//到后面为0的时候,因为为0,也不会影响答案
int k=(int)(log(double(r-l+1))/log(2.0));
return max(mi[l][k],mi[r-(1<<k)+1][k]);
}
int main()
{
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++) scanf("%lld",&a[i]);
f[0][0][0]=0;
f[0][0][1]=0;
init();
for (int i=0;i<=n;i++)
{
for (int j=0;j<=n-i;j++)
{
if (i==0&&j==0) continue;
int mis=MIN(1+m+i,n-m-j);
//因为减m,就保证了最后取的那些不会增加费用,和上面相呼应
if (i>0) f[i][j][0]=min(f[i-1][j][0]+mis,f[i-1][j][1]+mis*(i+j));
else f[i][j][0]=inf;
mis=MIN(1+m+i+1,n-m-j+1);
if (j>0) f[i][j][1]=min(f[i][j-1][1]+mis,f[i][j-1][0]+mis*(i+j));
else f[i][j][1]=inf;
}
}
ll tmp=inf;
for (int i=0;i<=n;i++) tmp=min(tmp,min(f[i][n-i][0],f[i][n-i][1]));
for (int i=1;i<=n;i++) tmp+=a[i];
printf("%lld",tmp);
return 0;
}