题意:
n个洞,m个公司,至少补k个洞,每个公司只能补Li到Ri之间的懂,并且费用是ci。问补至少k个洞的最小费用。
题解:
首先我么要这题要知道任意段区间之间的费用是多少,因为公司的区间是可以重合的,但是重合部分要多计算,那么我们可以用(n^3)的计算出任意段区间的费用。
接着我们就可以dp了,dp[i][j]表示前i个点补了k个洞的最小费用。状态方程和往常非常不同本来是要O(n^4)现在优化了一个地方O(n^3)
dp[i][j] = max{ dp[i-1][j] (表示不补i这个洞), dp[i-k][j-k] + cost[i-k+1][i] }
注意别爆int
#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
#include<map>
using namespace std;
typedef long long lld;
const int oo=0x3f3f3f3f;
const lld OO=1LL<<61;
const int MOD=1000000007;
#define maxn 305
lld dp[maxn][maxn];
lld cost[maxn][maxn];
/**
dp[i][j] = max{ dp[i-1][j] , dp[i-k][j-k] + cost[i-k+1][i] }
*/
int main()
{
int n,m,k,l,r,c;
while(scanf("%d %d %d",&n,&m,&k)!=EOF)
{
for(int i=0;i<maxn;i++)
for(int j=0;j<maxn;j++)
dp[i][j]=cost[i][j]=OO;
for(int k=1;k<=m;k++)
{
scanf("%d %d %d",&l,&r,&c);
for(int i=l;i<=r;i++)
for(int j=i;j<=r;j++)
cost[i][j]=min(cost[i][j],(lld)c);
}
dp[0][0]=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=n;j++)
{
dp[i][j]=dp[i-1][j];
for(int k=1;k<=i&&k<=j;k++)
{
dp[i][j]=min(dp[i][j],dp[i-k][j-k]+cost[i-k+1][i]);
}
}
}
if(dp[n][k]==OO)dp[n][k]=-1;
printf("%I64d\n",dp[n][k]);
}
return 0;
}
/**
10 4 6
7 9 11
6 9 13
7 7 7
3 5 6
10 7 1
3 4 15
8 9 8
5 6 8
9 10 6
1 4 2
1 4 10
8 10 13
10 1 9
5 10 14
*/