CF #1354 Educational Codeforces Round 87

F. Summoning Minions

贪心:每次一定取 \(k-1\) 个不删,然后每次取一个删一个,最后取 \(1\) 个保留。

对于每个点分别算贡献,即为对其他的贡献的 \(b_i\) 和(如果自己保留)贡献的 \(a_i\)

假设所有保留的为集合 \(A\),则 \(A\) 中的元素一定是按照 \(b_i\) 递增顺序加入。

因此按照 \(b_i\) 排序,进行 DP 即可。\(\mathcal O(n^2)\)

当然可以对每个东西和每个位置跑带权匹配,但我被卡了

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
using namespace std;

#define File(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)

template<class T> void upmax(T &x, T y){x = x>y ? x : y;}
template<class T> void upmin(T &x, T y){x = x<y ? x : y;}

struct item{
	int a, b, id;
};
item a[80];
int f[80][80];
bool from[80][80];
bool isA[80];
int A[80];

int main(){
	// File("cf1354f");
	int T;
	scanf("%d", &T);
	while(T--){
		int k, n;
		scanf("%d%d", &n, &k);
		for(int i=1; i<=n; i++)
			scanf("%d%d", &a[i].a, &a[i].b), a[i].id = i;
		sort(a + 1, a + 1 + n, [](item p, item q) {return p.b < q.b;});
		memset(f, 0x9f, sizeof(f));
		f[0][0] = 0;
		for(int i=1; i<=n; i++){
			f[i][0] = f[i-1][0] + a[i].b * (k - 1);
			for(int j=max(1, k - (n - i)), li=min(i, k); j<=li; j++){
				int tA = a[i].a + a[i].b * (j - 1) + f[i-1][j-1];
				int tB = a[i].b * (k - 1) + f[i-1][j];
				if(tA > tB)
					f[i][j] = tA, from[i][j] = true;
				else
					f[i][j] = tB, from[i][j] = false;
			}
		}
		for(int p=n, q=k; p!=0; --p){
			isA[p] = from[p][q];
			if(isA[p]) A[q] = a[p].id;
			q -= from[p][q];
		}
		printf("%d\n", n * 2 - k);
		for(int i=1; i<k; i++) printf("%d ", A[i]);
		for(int i=1; i<=n; i++)
			if(!isA[i]) printf("%d -%d ", a[i].id, a[i].id);
		printf("%d\n", A[k]);
	}
	return 0;
}

G. Find a Gift

因为不知道哪个是重物,很难处理,必须先找到一个重物作为切入点。

随机若干个物品和 \(1\) 称重,如果 \(1\) 较轻,则答案就是 \(1\)

否则认为 \(1\) 是重物,依次倍增,判断 \([1,2^k]\) 是否都是重物,找到第一个不是重物的区间,可以和前面全是重物的区间进行比较,二分即可。

几个部分询问次数都是 \(\log\) 级的。

#include <iostream>
#include <random>
using namespace std;

int ask(int l1, int r1, int l2, int r2){
	cout << "? " << r1 - l1 + 1 << ' ' << r2 - l2 + 1 << ' ' << '\n';
	for(int i=l1; i<=r1; i++)
		cout << i << ' ';
	cout << '\n';
	for(int i=l2; i<=r2; i++)
		cout << i << ' ';
	cout << endl;
	char res[10];
	cin >> res;
	if(res[0] == 'E') return 0;
	if(res[0] == 'F') return 1;
	if(res[0] == 'S') return 2;
	return -1;
}

int main(){
	cin.sync_with_stdio(false);
	cout.sync_with_stdio(false);
	int T;
	cin >> T;
	mt19937 rnd((unsigned long long)&T);
	while(T--){
		int n, k;
		cin >> n >> k;
		uniform_int_distribution<int> D(2, n);
		bool ok = false;
		for(int i=1; i<=25; i++){
			int pos = D(rnd);
			int r = ask(1, 1, pos, pos);
			if(r == 2){
				cout << "! " << 1 << endl;
				ok = true;
				break;
			}
		}
		if(ok) continue;
		int L, R;
		for(int i=1; i*2<=n; i<<=1){
			int r = ask(1, i, i + 1, 2 * i);
			if(r == 1){
				L = i + 1, R = 2 * i;
				break;
			}
			L = i * 2 + 1, R = n;
		}
		int res = R;
		while(L <= R){
			int mid = (L + R) >> 1;
			if(ask(1, mid - L + 1, L, mid) == 1)
				res = mid, R = mid - 1;
			else L = mid + 1;
		}
		cout << "! " << res << endl;
	}
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/RiverHamster/p/sol-cf1354.html