传送门
题意:
给一个区间[1,n],再给出m个区间 [li,ri] [ l i , r i ] 以及每个区间的维修成本 vi v i ,问修好k个不同的整点所需的最小成本。
(n≤300,m≤1e5)

Solution:
这道题首先想到了朴素的 n2m n 2 m 的dp(按照右端点排序,f[i][j][k]表示前i个区间,选了j个点,上一个选的右端点为k的最小代价),但是显然会T,转移时O(1)的所以无法优化,所以考虑优化状态:发现m太大,那么能否优化掉m呢?考虑预处理:dis[l][r]表示一次修理l到r这段区间的最小花费(详见代码),然后就不需要枚举m了,此时我们的dp可以转化为f[i][j]表示前i个点我们维修了j个点的最小代价,转移可以枚举每次维修的长度,这样复杂度就可以降到 n3 n 3 了。

代码:

#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int m,n,k;
struct qj{
    long long l,r,v;
}q[100010];
long long dis[310][310];
long long f[310][310];
long long ans=1e18;
const long long inf=1e18;
int main()
{
    scanf("%d%d%d",&n,&m,&k);
    for (int i=0;i<=n;i++)
        for (int j=0;j<=n;j++)
            dis[i][j]=inf,f[i][j]=inf;
    for (int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&q[i].l,&q[i].r,&q[i].v);
        for (int j=q[i].l;j<=q[i].r;j++)
        {
            dis[q[i].l][j]=min(dis[q[i].l][j],q[i].v);
            dis[j][q[i].r]=min(dis[j][q[i].r],q[i].v);
        }
    }
    for (int i=0;i<=n;i++)
        f[i][0]=0;
    for (int i=1;i<=n;i++)
    {
        for (int j=1;j<=i;j++)
        {
            for (int now=0;now<=j;now++)
            {
                f[i][j]=min(f[i][j],f[i-now][j]);
                f[i][j]=min(f[i][j],f[i-now][j-now]+dis[i-now+1][i]);
            }
        }
    }
    for (int i=k;i<=n;i++)
        ans=min(ans,f[n][i]);
    if (ans<1e18) printf("%I64d",ans);
    else printf("-1");
}