2017icpc北京 Pangu and Stones
题意&思路:
给n个石头,每次只能合并连续的l~r块,合并的代价是每堆石子的权值和,问最小的代价是多少。
看起来就是石子合并的进阶版(实际上也是),但是好难好难好难啊。看题解都看不懂,要感谢学长的讲解。
记一下不太懂得部分:
dp[i][j][k]是i~j区间划分为k堆得代价,如果l≤k≤r得话,就可以组成一堆,代价就是i~j所有石子得权值和。p就是在i~j中得一点,划分区间。
dp[i][i][1]=0,dp[i][j][len]=0,石子自己一堆是初始状态,不需要代价;i~j的石子本身就是len堆,所以也不需要代价。
为什么dp这么难。
代码:
#include<bits/stdc++.h>
#define pii pair<int,int>
#define ll long long
const int N=1e6+10;
const int mod=1e7+9;
const int maxn=0x3f3f3f3f;
const int minn=0xc0c0c0c0;
const int inf=99999999;
using namespace std;
int a[110],dp[110][110][110],sum[110]={0};
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int n,l,r,len,i,j,k,p;
while(cin>>n>>l>>r)
{
for(i=1;i<=n;i++)
{
cin>>a[i];
sum[i]=sum[i-1]+a[i];
}
memset(dp,maxn,sizeof(dp));
for(i=1;i<=n;i++)
dp[i][i][1]=0;
for(len=1;len<=n;len++)
{
for(i=1;i<=n-len+1;i++)
{
j=i+len-1;
//dp[i][j][len]=0;
for(k=2;k<=len;k++)
{
for(p=i;p<=j;p++)
dp[i][j][k]=min(dp[i][j][k],dp[i][p][1]+dp[p+1][j][k-1]);
if(k>=l && k<=r)
dp[i][j][1]=min(dp[i][j][1],dp[i][j][k]+sum[j]-sum[i-1]);
}
}
}
if(dp[1][n][1]>=maxn) dp[1][n][1]=0;
cout<<dp[1][n][1]<<endl;
}
return 0;
}