区间DP
区间DP
https://oi-wiki.org/dp/interval/
例1:石子合并
破环成链
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=205;
inline int read() {
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return f*x;
}
int n,sum[N][N],a[N];
int f[N][N],g[N][N];//f -min g -max
inline void Max(int &x,int y){if(x<y)x=y;}
inline void Min(int &x,int y){if(x>y)x=y;}
int main() {
n=read();
for(int i=1;i<=n;i++)
a[i+n]=a[i]=read();
for(int i=1;i<=2*n;i++)
for(int j=i;j<=2*n;j++)
for(int k=i;k<=j;k++)
sum[i][j]+=a[k];
for(int len=1;len<=n;len++)
for(int l=1;l<(n<<1)&&l+len<(n<<1);l++) {
int r=l+len;
f[l][r]=0x3f3f3f3f;
for(int k=l;k<r;k++) {
f[l][r]=min(f[l][r],f[l][k]+f[k+1][r]+sum[l][r]);
g[l][r]=max(g[l][r],g[l][k]+g[k+1][r]+sum[l][r]);
}
}
int ans1=0x3f3f3f3f,ans2=0;
for(int i=1;i<=n;i++) {
Min(ans1,f[i][i+n-1]);
Max(ans2,g[i][i+n-1]);
}
printf("%d\n%d\n",ans1,ans2);
return 0;
}
例2:Polygon多边形
#include<bits/stdc++.h>
const int inf=0x3f3f3f3f;
int n,ans=-inf;
int a[105];
int f[150][150],g[150][150];
char c[105];
int min(int x,int y){
return x>y?y:x;
}
int max(int x,int y){
return x>y?x:y;
}
int main(){
scanf("%d\n",&n);
for(int i=1;i<=n;i++){
scanf("%c %d",&c[i],&a[i]);getchar();
a[n+i]=a[i];c[n+i]=c[i];
}
for(int i=1;i<=(n<<1);i++)
for(int j=1;j<=(n<<1);j++)
f[i][j]=-inf,g[i][j]=inf;
for(int i=1;i<=(n<<1);i++)
f[i][i]=g[i][i]=a[i];
for(int len=2;len<=n;len++){
for(int i=1,j=len;j<=(n<<1);i++,j++){
for(int k=i;k<j;k++){
if(c[k+1]=='x'){
f[i][j]=max(f[i][j],max(f[i][k]*f[k+1][j],max(g[i][k]*g[k+1][j],max(f[i][k]*g[k+1][j],g[i][k]*f[k+1][j]))));
g[i][j]=min(g[i][j],min(f[i][k]*f[k+1][j],min(g[i][k]*g[k+1][j],min(f[i][k]*g[k+1][j],g[i][k]*f[k+1][j]))));
}
else if(c[k+1]=='t'){
f[i][j]=max(f[i][j],f[i][k]+f[k+1][j]);
g[i][j]=min(g[i][j],g[i][k]+g[k+1][j]);
}
}
}
}
for(int i=1;i<=n;i++)
ans=max(ans,f[i][i+n-1]);
printf("%d\n",ans);
for(int i=1;i<=n;i++)
if(f[i][i+n-1]==ans)
printf("%d ",i);
return 0;
}
例3:能量项链
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=205;
inline int read() {
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return f*x;
}
int n;
ll f[N][N],ans,a[N];
inline void Max(ll &x,ll y){if(x<y)x=y;}
int main() {
n=read();
for(int i=1;i<=n;i++)
a[i+n]=a[i]=read();
for(int len=1;len<=n;len++)
for(int l=1;l<=(n<<1)&&l+len<=(n<<1);l++) {
int r=l+len;
for(int k=l+1;k<=r;k++)
Max(f[l][r],f[l][k-1]+f[k][r]+a[l]*a[r+1]*a[k]);
}
for(int i=1;i<=n;i++)
Max(ans,f[i][i+n-1]);
printf("%lld\n",ans);
return 0;
}
例4:金字塔
dfs序的性质,
\([l,k]\) 是一棵子树,则 \(l\) 和 \(k\) 为根节点,即\(s[l]=s[k]\)
$ dp[l][r]=dp[l][r]+dp[l+1][k-1]*dp[k][r] $
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=305;
const int P=1e9;
inline int read() {
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return f*x;
}
int n;
char s[305];
ll f[N][N];
int main() {
scanf("%s",s+1);
n=strlen(s+1);
for(int i=1;i<=n;i++) f[i][i]=1;
for(int len=1;len<=n;len++)
for(int l=1;l<=n;l++) {
int r=l+len;
if(r>n) break;
for(int k=l+2;k<=r;k++)
if(s[k]==s[l])
f[l][r]=(f[l][r]+f[l+1][k-1]*f[k][r]%P)%P;
}
printf("%lld\n",f[1][n]);
return 0;
}
例5:Treats for the Cows G/S
\(r-l+第几天卖出=n\)
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=2055;
inline int read() {
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return f*x;
}
int n;
int f[N][N],ans,a[N];
inline void Max(int &x,int y){if(x<y)x=y;}
int main() {
n=read();
for(int i=1;i<=n;i++) {
a[i]=read();
f[i][i]=a[i]*n;
}
for(int len=1;len<=n;len++)
for(int l=1;l<=n;l++) {
int r=l+len;
if(r>n) break;
if(l==r) f[l][r]=a[l]*n;
else {
Max(f[l][r],f[l+1][r]+(n-r+l)*a[l]);
Max(f[l][r],f[l][r-1]+(n-r+l)*a[r]);
}
}
printf("%d\n",f[1][n]);
return 0;
}