zoukankan      html  css  js  c++  java
  • 「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

  • 相关阅读:
    组织机构数据隔离(上级可看下级,同级屏蔽)的高效实现思路
    .NET Core 3.x 基于AspectCore实现AOP,实现事务、缓存拦截器
    .NET Core 3.x 基于Autofac的AOP缓存
    Web开发中【密码加密】详解
    python多线程 DBUtils操作数据库
    处理MariaDB Galera cluster初始化和启动报错两例
    搭建MariaDB Galera Cluster集群 10.3.8
    AzureWeb应用作为客户端携带证书访问其他链接办法
    CTF
    [KuangBin专题四]Silver Cow Party
  • 原文地址:https://www.cnblogs.com/Alfalfa-w/p/14731709.html
Copyright © 2011-2022 走看看