zoukankan      html  css  js  c++  java
  • 2019杭电多校一 C. Milk (dp)

    大意: $n*m$棋盘, 初始位置$(1,1)$, 横坐标为$frac{m+1}{2}$时可以向下走, 否则只能左右走, 每走一步花费$1$秒. 有$k$管奶, 第$i$罐位置$(r_i,c_i)$, 要花费$t_i$的时间去喝. 对于所有的$1le ile k$, 求出喝完$i$管奶最短用时.

    实现略复杂的$dp$题, 直接按照官方题解写了.

    主要思路是对每一行求出向左/向右喝$x$罐奶的最少用时, 然后$dp$合并答案.

    #include <iostream>
    #include <algorithm>
    #include <cstdio>
    #include <queue>
    #define REP(i,a,n) for(int i=a;i<=n;++i)
    #define PER(i,a,n) for(int i=n;i>=a;--i)
    #define x first
    #define y second
    #define pb push_back
    using namespace std;
    typedef long long ll;
    typedef pair<int,int> pii;
    const ll INF = 1e15;
    const int N = 1e4+10;
    int n, m, k, b[N];
    struct {int x,y,t;} a[N];
    ll ans[N];
    vector<pii> v[N];
    vector<ll> solve(vector<pii> a, int s, int x) {
    	a.insert(a.begin(),pii(s,0));
    	vector<ll> ret(a.size(),INF), t(ret);
    	ret[0] = x==-1?0:abs(x-s);
    	t[0] = 0;
    	for (int i=1; i<a.size(); ++i) {
    		int len = abs(a[i].x-a[i-1].x);
    		REP(j,0,i-1) t[j]+=len;
    		PER(j,1,i) t[j]=min(t[j],t[j-1]+a[i].y);
    		REP(j,1,i) ret[j]=min(ret[j],t[j]+(x==-1?0:abs(x-a[i].x)));
    	}
    	return ret;
    }
    vector<ll> Merge(const vector<ll> &L, const vector<ll> &R) {
    	vector<ll> ret(L.size()+R.size()-1,INF);
    	for (int i=0;i<L.size();++i) {
    		for (int j=0;j<R.size();++j) {
    			ret[i+j] = min(ret[i+j], L[i]+R[j]);
    		}
    	}
    	return ret;
    }
    
    void work() {
    	scanf("%d%d%d", &n, &m, &k);
    	*b = 0;
    	REP(i,1,k) {
    		scanf("%d%d%d",&a[i].x,&a[i].y,&a[i].t);
    		b[++*b] = a[i].x;
    	}
    	b[++*b] = 1;
    	sort(b+1,b+1+*b),*b=unique(b+1,b+1+*b)-b-1;
    	REP(i,1,*b) v[i].clear();
    	REP(i,1,k) { 
    		a[i].x=lower_bound(b+1,b+1+*b,a[i].x)-b;
    		v[a[i].x].pb(pii(a[i].y,a[i].t));
    		ans[i] = INF;
    	}
    	REP(i,1,*b) sort(begin(v[i]),end(v[i]));
    	auto g = solve(v[1],1,-1);
    	for (int i=0;i<g.size();++i) {
    		ans[i] = min(ans[i], g[i]);
    	}
    	int cur = 0;
    	vector<ll> f[2];
    	f[0] = solve(v[1],1,(m+1)/2);
    	REP(i,2,*b) {
    		cur ^= 1;
    		auto p = lower_bound(begin(v[i]),end(v[i]),pii((m+1)/2,0));
    		vector<pii> L(begin(v[i]),p), R(p,end(v[i]));
    		reverse(begin(L),end(L));
    		auto f0 = solve(L,(m+1)/2,(m+1)/2), f1 = solve(R,(m+1)/2,(m+1)/2);
    		auto g0 = solve(L,(m+1)/2,-1), g1 = solve(R,(m+1)/2,-1);
    		g0 = Merge(f1,g0), g1 = Merge(f0,g1);
    		auto g = g0;
    		for (int j=0;j<g.size();++j) {
    			g[j] = min(g[j], g1[j]);
    		}
    		g = Merge(f[!cur],g);
    		f[cur] = Merge(f[!cur],Merge(f0,f1));
    		for (int j=0;j<g.size();++j) {
    			ans[j] = min(ans[j], g[j]+b[i]-b[i-1]);
    			f[cur][j] += b[i]-b[i-1];
    		}
    	}
    	REP(i,1,k) {
    		if (i==k) printf("%lld
    ",ans[i]);
    		else printf("%lld ",ans[i]);
    	}
    }
    
    
    int main() {
    	int t;
    	scanf("%d", &t);
    	while (t--) work();
    }
    
  • 相关阅读:
    C++ 不用 < > 与 : ?运算符判断 a,b大小
    CentOS7 MariaDB10
    CentOS Linux 挂载NTFS
    Linux访问Windows共享
    Emacs配置与插件集记录
    驱动精妙耍流氓,强制安装"新毒霸"
    C# TextBox控件之大小写自动转换
    生活随笔
    显示外网IP
    MySql
  • 原文地址:https://www.cnblogs.com/uid001/p/11249158.html
Copyright © 2011-2022 走看看