U33405 纽约

U33405 纽约

花费 \(w\) 元可以购买一辆容量为 \(w\) 的车
现在你有 \(n <= 2000\) 个物品, 搬运策略: 一直搬能放下里面最重的, 直到任意物品都不能搬上为止
求满足运送次数 \(<= R\) 的情况下买车花费的最少钱数

Solution

二分花钱数, 模拟搬运过程, 复杂度 \(O(n^{2}\log{n})\)
因为物品排序后有单调性, 且只能用一次(搬一次), 使用链表优化, 总复杂度\(O(n \log{n})\)

可是这题我认为有问题
upd: 哦原来后面有说
问题出在在符合搬运策略的情况下, 出钱数与搬运次数不符合单调性
所以最后加了个往前面检查多次查看是否合法, 取较小值

Code

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<climits>
#define LL long long
#define REP(i, x, y) for(int (i) = (x);(i) <= (y);(i)++)
using namespace std;
int RD(){
    int out = 0,flag = 1;char c = getchar();
    while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
    while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
    return flag * out;
    }
const int maxn = 4019;
int num, R;
int w[maxn], l[maxn], r[maxn];
int minn, maxx;
bool cmp(int a, int b){return a > b;}
void init(){
	REP(i, 1, num)l[i] = i - 1, r[i] = i + 1;
	r[0] = 1;
	}
bool check(int k){
	init();
	int tim = 0, tot = 0, now = 0, left = num;
	while(1){
		now = r[0], tot = 0;
		tim++;
		while(now <= num){//运一次
			if(tot + w[now] <= k){//不超重
				tot += w[now];
				r[l[now]] = r[now];//链表删除
				l[r[now]] = l[now];
				left--;
				if(!left){//所有东西搬完检查次数
					if(tim <= R)return 1;
					return 0;
					}
				}
			now = r[now];
			}
		if(tim > R)return 0;
		}
	}
int search(int l, int r){
	int ans = -1;
	while(l <= r){
		int mid = (l + r) >> 1;
		if(check(mid))ans = mid, r = mid - 1;
		else l = mid + 1;
		}
	return ans;
	}
int ans;
int main(){
	num = RD(), R = RD();
	REP(i, 1, num)w[i] = RD(), minn = min(minn, w[i]), maxx += w[i];
	sort(w + 1, w + 1 + num, cmp);
	int temp = search(minn, maxx);
	for(ans = temp - 51;ans <= temp && !check(ans);ans++);
	printf("%d\n", ans);
	return 0;
	}
posted @ 2018-10-06 17:41  Tony_Double_Sky  阅读(128)  评论(0编辑  收藏  举报