zoukankan      html  css  js  c++  java
  • 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 * 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
    ", 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 << ' ' << '
    ';
    	for(int i=l1; i<=r1; i++)
    		cout << i << ' ';
    	cout << '
    ';
    	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;
    }
    
  • 相关阅读:
    POJ 1936 All in All
    POJ 2305 Basic remains
    POJ 2081 Recaman's Sequence
    MFC MDI 窗口函数执行顺序
    decompose
    不新建一个文档
    code mistake
    ...
    paper
    stereo
  • 原文地址:https://www.cnblogs.com/RiverHamster/p/sol-cf1354.html
Copyright © 2011-2022 走看看