区间DP 模板 282. 石子合并
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#define rg register
using namespace std;
typedef long long ll;
int sread()
{
int x=0,f=1;char c=getchar();
while(c>'9'||c<'0') {if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
return f*x;
}
const int maxn=40010;
int n,len;
int a[maxn],sum[maxn];
int dp[350][350];
int main()
{
n=sread();
for(rg int i=1;i<=n;++i)
{
a[i]=sread();
sum[i]=sum[i-1]+a[i];
}
memset(dp,0x3f,sizeof(dp));
for(rg int i=1;i<=n;++i) dp[i][i]=0;
for(rg int len=2;len<=n;++len)
{
for(rg int i=1;i<=n-len+1;++i)
{
int j=len+i-1;
for(rg int k=i;k<j;++k)
{
dp[i][j]=min(dp[i][j],dp[i][k]+dp[k+1][j]+sum[j]-sum[i-1]);
}
}
}
cout<<dp[1][n]<<endl;
return 0;
}
P3205 [HNOI2010]合唱队
算法分析
代码实现
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstring>
#define rg register
using namespace std;
typedef long long ll;
int sread()
{
int x=0,f=1;char c=getchar();
while(c>'9'||c<'0') {if(c=='-')f=-1;c=getchar();}
while(c>='0'&&c<='9') {x=x*10+c-'0';c=getchar();}
return f*x;
}
const int p=19650827;
const int maxn=1010;
int n;
int a[maxn];
int dp[maxn][maxn][2];
int main()
{
cin>>n;
for(rg int i=1;i<=n;i++) cin>>a[i];
for(rg int i=1;i<=n;i++) dp[i][i][0]=1;
for(rg int len=2;len<=n;++len)
{
for(rg int i=1;i<=n-len+1;++i)
{
int j=len+i-1;
if(a[j]>a[j-1]) //如果右端点的数大于上一个数且上一个数插入在了右端点
dp[i][j][1] += dp[i][j-1][1];
if(a[j]>a[i]) //如果右端点的数大于左端点且上一个数插入在了左端点
dp[i][j][1] += dp[i][j-1][0];
if(a[i]<a[j]) //如果左端点的数小于下一个数且上一个数插入在了右端点
dp[i][j][0] += dp[i+1][j][1];
if(a[i]<a[i+1]) //如果左端点的数小于右端点且上一个数插入在了左端点
dp[i][j][0] += dp[i+1][j][0];
dp[i][j][1]%=p;
dp[i][j][0]%=p;
}
}
cout<<(dp[1][n][0]+dp[1][n][1])%p<<endl;
return 0;
}