区间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;
}
posted @ 2020-08-15 11:07  ke_xin  阅读(29)  评论(0编辑  收藏  举报