呜呜呜,我真的太水了。
没有人说过,只要是环形的题,就要把它复制一下接在后面。然而我。。。。就犯了这米杀的错误。
这道题
关建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; }