石子合并
https://www.luogu.com.cn/problem/P1880
一道区间dp题目。
用d[i][j]表示从i到j的最大/最小得分,那么依次枚举长度len,坐标i和j,三层循环就可以dp递推求得最值了(听说这是道NOI题目)
记得使用前缀和哦。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<ctype.h> #define INF 0x3f3f3f3f using namespace std; inline int read() { int x=0,w=1;char c=getchar(); while(!isdigit(c)){ if(c=='-')w=-1; c=getchar(); } while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar(); return x*w; } const int maxn=105; int a[maxn],sum[maxn],d[maxn][maxn],d2[maxn][maxn]; int main() { int n=read(); for(int i=1;i<=n;i++)a[i]=read(); for(int i=1;i<=n;i++)sum[i]=sum[i-1]+a[i];//前缀和 for(int len=2;len<=n;len++) for(int i=1;i<=n-len+1;i++) { int j=i+len-1; d[i][j]=INF; for(int k=i;k<j;k++) { if(d[i][j]>d[i][k]+d[k+1][j]+sum[j]-sum[i-1]) d[i][j]=d[i][k]+d[k+1][j]+sum[j]-sum[i-1]; if(d2[i][j]<d2[i][k]+d2[k+1][j]+sum[j]-sum[i-1]) d2[i][j]=d2[i][k]+d2[k+1][j]+sum[j]-sum[i-1]; } } printf("%d\n%d\n",d[1][n],d2[1][n]); return 0; }
勇于实践的小伙伴们可以惊讶的发现:它爆零了!
emmm我们仔细审题会发现这是一个环。
所以不要着急我们给它再加n个数复制一遍就可以AC了(发扬了dp用内存换速度的优良作风)
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<ctype.h> #define INF 0x3f3f3f3f using namespace std; inline int read() { int x=0,w=1;char c=getchar(); while(!isdigit(c)){ if(c=='-')w=-1; c=getchar(); } while(isdigit(c))x=(x<<3)+(x<<1)+(c^48),c=getchar(); return x*w; } const int maxn=105*2; int a[maxn],sum[maxn],d[maxn][maxn],d2[maxn][maxn]; int main() { int n=read(); for(int i=1;i<=n;i++)a[i]=a[i+n]=read(); for(int i=1;i<=(n+n);i++)sum[i]=sum[i-1]+a[i];//前缀和 for(int len=2;len<=n;len++) for(int i=1,j=i+len-1;i<n+n and j<n+n ;i++,j=i+len-1) { d[i][j]=INF; for(int k=i;k<j;k++) { if(d[i][j]>d[i][k]+d[k+1][j]+sum[j]-sum[i-1]) d[i][j]=d[i][k]+d[k+1][j]+sum[j]-sum[i-1]; if(d2[i][j]<d2[i][k]+d2[k+1][j]+sum[j]-sum[i-1]) d2[i][j]=d2[i][k]+d2[k+1][j]+sum[j]-sum[i-1]; } } int ans1=INF,ans2=0; for(int i=1;i<=n;i++)ans1=min(ans1,d[i][i+n-1]),ans2=max(ans2,d2[i][i+n-1]); printf("%d\n%d\n",ans1,ans2); return 0; }
当然,这个直接把n<<1的作死做法是没有办法干过大多数题目的。于是我们就需要对dp进行平行四边形优化
但是我没学……以后学了单独写一篇题解吧。
扩展:这道题的数据范围是n<=100,而我们给它还扩充到了n<=200。那么如果n更大呢?比如n<=40000?
这里有一道题目洛谷P5569
是的我们没法再用40000*40000的dp做了。
我也不会
这已经不是dp的问题了!但是还是给大佬们一个传送门