cf 1106e dp

题意: 父亲在时间流水(n 1e5)上选择东西(k 1e5),每个有它的价值w和可被选择起止时间s,t,在选择之后以及到时间d,不可再选,父亲有固有的选择策略。

但是女儿可以打断父亲m(200)次,使其不能选择,求最后的最小值是多少

思路:dp  假设不存在打断的情况,那么父亲就按照一个固有的顺序选择了。d[i][j] 表示在打断i次 ,走到  j 可以获得最小值。

按照时间的顺序, i可能打断那么就是 d[i+1[j+1]的时候,不打断,父亲按照固有策略去选择。

值得学习的地方是,利用map的排序来 以及它的erase 和insert来表示了在时间i的选择的可能和最佳情况

#include<bits/stdc++.h>
using namespace std;

#define ll long long
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define all(v) v.begin(),v.end()
#define mem(a) memset(a,0,sizeof(a))

const int M = 202;
const int N = 1e5+4;
const ll mod =1e9+7;
const ll INF = 1e18+4;
const double eps = 1e-7;

struct node{
    int d,w;
    //题目要求的父亲的选择策略
    friend bool operator <(node a,node b){
        return a.w>b.w || (a.w==b.w && a.d>b.d );
    }
};

map<node,int>choice;
vector<node>V[N],T[N];
node a[N];
ll d[M][N];
void insert(node x){
    if(choice.count(x))
        choice[x]++;
    else choice[x]=1;
}

void erase(node x){
    choice[x]--;
    if(choice[x]==0)
        choice.erase(x);
}
int main(){
    int n,m,k;
    cin>>n>>m>>k;

    for(int i=0;i<k;++i){
        int s,t,d,w;
        cin>>s>>t>>d>>w;
        V[s].pb(node{d,w});
        T[t+1].pb(node{d,w});
    }

    for(int i=1;i<=n;++i){
        for(int j=0;j<V[i].size();++j)
            insert(V[i][j]);
        for(int j=0;j<T[i].size();++j)
            erase(T[i][j]);
        //这是父亲要选择的最佳
        if(choice.size()){
            a[i]=  (*choice.begin()).first;
        }
        else a[i] =node{i,0};
    }

   for(int i=0;i<=m;++i)
        for(int j=0;j<=n+111;++j)
            d[i][j]=INF;

    ll ans =INF;
    d[0][1]=0;
    for(int j=0;j<=m;++j){
        for(int i=1;i<=n;++i){
            //假设在i时间打断
            d[j+1][i+1] = min(d[j+1][i+1],d[j][i]);
            //不打断,则父亲选择a[i] 之后的min是因为可能还有其他选择方法导致的可能
            d[j][a[i].d+1] = min(d[j][a[i].d+1],d[j][i]+a[i].w);
        }
        ans = min(ans,d[j][n+1]);
    }
    cout<<ans<<endl;
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/wjhstudy/p/10350414.html