• 「CF 1483E」Vabank(交互,构造)


    题目链接

    题意:

    你要猜出一个整数 (M)(0 le M le 10^{14}))。一开始,你有 (1) 元钱。每次,你可以询问一个整数 (X),接下来:

    • (X le M),你会获得 (X) 元钱;
    • (X > M),你会损失 (X) 元钱;
    • 你能知道是 (X le M) 还是 (X > M)

    任何时刻,你要保证你的存款非负。你要在 (105) 次询问内问出 (M)

    思路:

    维护当前 (M) 所在的区间 ([L, R)),每询问一次就对这个区间进行收缩。

    (L) 足够大时,只要询问 (L) 就能白嫖 (L) 元。所以我们先要把 (L, R) 变为同一级别。只要依次询问 (1, 2, 4, 8, ldots) 即可。

    发现当 (L, R) 同级时,询问的 (X) 也与它们同级。因此只要有一定的本金,一次收益和一次损失可以看作抵消。

    更好的解释是,一次收益和一次损失总共最多亏损 (R - L) 元,而随着询问次数增多 (R - L) 指数级减少,所以 (sum R - L)(O(M)) 的。

    所以,我们设计 (f_{i, j}) 表示用 (i) 次询问,当前还能损失 (j) 次时能问出的最大区间长度。那么有转移:

    • (f_{i, j} = f_{i - 1, j - 1} + f_{i - 1, j + 1} (j > 0))
    • (f_{i, 0} = f_{i - 1, 1})

    按照转移式进行询问即可。

    代码:

    #include <bits/stdc++.h>
    
    #define rep(i, a, b) for (int i = (a); i <= int(b); i++)
    #define per(i, a, b) for (int i = (a); i >= int(b); i--)
    
    using namespace std;
    
    typedef long long ll;
    
    int T;
    
    bool ask(ll x) {
    	printf("? %lld
    ", x);
    	fflush(stdout);
    	char s[10];
    	scanf("%s", s);
    	return s[0] == 'L' ? 1 : 0;
    }
    
    void putans(ll m) {
    	printf("! %lld
    ", m);
    	fflush(stdout);
    }
    
    ll dp[70][70];
    
    void init(int n) {
    	rep(i, 0, n) {
    		dp[0][i] = 1;
    	}
    	rep(i, 1, n) {
    		dp[i][0] = dp[i - 1][1];
    		rep(j, 1, n - i) {
    			dp[i][j] = dp[i - 1][j - 1] + dp[i - 1][j + 1];
    		}
    	}
    }
    
    ll get(int a, int b, ll l, ll r) {
    	if (r - l == 1) {
    		return l;
    	}
    	if (b == 0) {
    		ask(l);
    		return get(a - 1, 1, l, r);
    	}
    	ll c = min(dp[a - 1][b - 1], r - l - 1);
    	if (!ask(l + c)) {
    		return get(a - 1, b - 1, l, l + c);
    	} else {
    		return get(a - 1, b + 1, l + c, r);
    	}
    }
    
    void work() {
    	if (!ask(1)) {
    		return putans(0);
    	}
    	ll l = 0, r = 0;
    	rep(i, 1, 46) {
    		if (!ask(1ll << i)) {
    			l = 1ll << (i - 1);
    			r = 1ll << i;
    			break;
    		}
    	}
    	if (!l) {
    		l = 1ll << 46;
    		r = ll(1e14) + 1;
    	}
    	int k = 0;
    	rep(i, 0, 59) {
    		if (dp[i][1] >= r - l) {
    			k = i;
    			break;
    		}
    	}
    	rep(i, 1, 6) {
    		ask(l);
    	}
    	ll ans = get(k, 1, l, r);
    	putans(ans);
    }
    
    int main() {
    	init(60);
    	scanf("%d", &T);
    	while (T --> 0) {
    		work();
    	}
    	return 0;
    }
    

    评价:

    思维难度:5/10

    代码难度:3/10

    评分:3/10

  • 相关阅读:
    hdu 3666 差分约束系统
    hdu 1198农田灌溉
    常微分方程(阿諾爾德) Page 45 相空間,相流,運動,相曲線 註記
    高等微積分(高木貞治) 1.4節 例2
    常微分方程(阿諾爾德) Page 45 相空間,相流,運動,相曲線 註記
    解析函數論 Page 29 命題(2) 函數模的有界性
    高等微積分(高木貞治) 1.4節 例2
    解析函數論 Page 29 命題(1) 有界閉集上的一致連續性
    解析函數論 Page 29 命題(3) 模的下界的可達性
    解析函數論 Page 29 命題(2) 函數模的有界性
  • 原文地址:https://www.cnblogs.com/Alfalfa-w/p/14731709.html
Copyright © 2020-2023  润新知