Codeforces Round #730 (Div. 2) A~D1 题解

康复训练.jpg

A.Exciting Bets

题意

给出两个数 a , b a,b a,b,每次操作可以:

  1. a++;
  2. a–,b–.

问在任意次操作后最大可能的 g c d ( a , b ) gcd(a,b) gcd(a,b)是多少,且问得到这个结果至少需要操作几次.

分析

根据定理 g c d ( a , b ) = g c d ( a , a − b ) gcd(a,b)=gcd(a,a-b) gcd(a,b)=gcd(a,ab),由于 a − b a-b ab不变,找到离 a a a最近的 a − b a-b ab的倍数即可.

代码

#include <bits/stdc++.h>
#define fors(i, a, b) for(int i = (a); i <= (b); ++i)
#define lson k<<1
#define rson k<<1|1
#define pb push_back
#define lowbit(x) ((x)&(-(x)))
#define mem(a) memset(a, 0, sizeof(a))
#define IOS ios::sync_with_stdio(false), cin.tie(0)
#define int long long
const int inf = 0x3f3f3f3f;
const double dinf = 1e100;
typedef long long ll;
//const ll linf = 9223372036854775807LL;
// const ll linf = 1e18;
using namespace std;

signed main()
{
    IOS;
    int t;
    cin >> t;
    while(t--)
    {
        int x, y;
        cin >> x >> y;
        if(x == y){
        	cout << "0 0" << endl;
        	continue;
		}
        int d = abs(x - y);
        cout << d << ' ';
        if(d == 1){
        	cout << 0 << endl;
        	continue;
		}
		x = min(x, y);
		cout << min(abs((x % d) - d), x % d) << endl;
    }
    return 0;
}

B. Customising the Track

题意

给一个数组,你可以自由地以整数为单位分配其中的元素(即保证整个数组的数都是非负数,且数组总和不变即可),要求 ∑ i = 1 n ∑ j = i + 1 n ∣ a i − a j ∣ \sum_{i=1}^n \sum_{j=i+1}^n|a_i-a_j| i=1nj=i+1naiaj最小.

分析

假设数组的总和是 s u m sum sum.

贪心,确保 ∣ a j − a i ∣ |a_j-a_i| ajai尽量小,只要让整个数组所有数都尽量接近平均数即可。对平均数向下取整得到 a v r avr avr,则假设有 x x x个数能修改成 a v r avr avr,那么剩下的 n − x n-x nx个数就是 a v r + 1 avr+1 avr+1,这个时候的所求结果就是 x ⋅ ( n − x ) x · (n-x) x(nx),一定为最小。

很容易知道 x = s u m − a v r ⋅ n x=sum-avr·n x=sumavrn.

代码

/**
  * @file    :debug.cpp
  * @brief   :Round 730
  * @date    :2021-07-07
  * @Motto   :Love Sakurai Yamauchi Forever
  */
#include <bits/stdc++.h>
#define fors(i, a, b) for(int i = (a); i <= (b); ++i)
#define lson k<<1
#define rson k<<1|1
#define pb push_back
#define lowbit(x) ((x)&(-(x)))
#define mem(a) memset(a, 0, sizeof(a))
#define IOS ios::sync_with_stdio(false), cin.tie(0)
#define int long long
const int inf = 0x3f3f3f3f;
const double dinf = 1e100;
typedef long long ll;
//const ll linf = 9223372036854775807LL;
// const ll linf = 1e18;
using namespace std;
const int maxn = 2e5 + 10;
int a[maxn];
signed main()
{
    IOS;
    int t;
    cin >> t;
    while(t--)
    {
        int n;
        cin >> n; int sum = 0;
        fors(i, 1, n) cin >> a[i], sum += a[i];
        int avr = sum / n;
        cout << (sum - avr * n) * (n - (sum - avr * n)) << endl;
    }
    return 0;
}

C. Need for Pink Slips

本题读懂题即可AC.

题意

现有三个物品 C , M , P C,M,P C,M,P,随机从他们中取一个,被取到的概率分别为 c , m , p c,m,p c,m,p. 你的目标是取到 P P P. 另外,还有一个小数 v v v v v v是这样起作用的:

  1. 如果取到了 P P P,直接结束.
  2. 如果取到了 A ≠ P A \neq P A=P,且 0 < a ≤ v 0 < a \leq v 0<av,那么 a a a变为0,且状态变为不可用,剩下的可用物品将概率 a a a平分(例如剩下2个都可用,那么每个都加上 a 2 a \over 2 2a;如果只有一个可用,就让它加上 a a a)
  3. 如果 a > v a>v a>v,那么 a a a变为 a − v a-v av,剩下的可用物品将概率 v v v平分.

概率为0的物品当然抽不到啦

若抽 x x x次抽到了 P P P,问 x x x的期望.

分析

裸dfs,讨论一下各个状态。假设每层递归当前的概率为 N N N,每层递归都从 c , m , p c,m,p c,m,p中选一个,选到 c c c或者 m m m时,按题目要求修改 c , m , p c,m,p c,m,p,然后递归下一层,下一层的概率为 N ⋅ a N·a Na; 选到 p p p时,答案加上 N ⋅ p ⋅ 当 前 递 归 抽 的 次 数 N·p·当前递归抽的次数 Np. 最后输出答案,注意一下精度即可。当 N < 精 度 N<精度 N<时,就不再向下递归了。

注意

由于 d o u b l e double double数据容易失真,建议不要使用 = = 、 > 、 < ==、>、< ==><,自己写一个基于精度的比较函数.(否则过不了第三个样例)

代码

#include <bits/stdc++.h>
#define fors(i, a, b) for(int i = (a); i <= (b); ++i)
#define lson k<<1
#define rson k<<1|1
#define pb push_back
#define lowbit(x) ((x)&(-(x)))
#define mem(a) memset(a, 0, sizeof(a))
#define IOS ios::sync_with_stdio(false), cin.tie(0)
#define int long long
const int inf = 0x3f3f3f3f;
const double dinf = 1e100;
typedef long long ll;
//const ll linf = 9223372036854775807LL;
// const ll linf = 1e18;
using namespace std;
double ans = 0;
double v;
int cmp(double x, double y)
{
    if(fabs(x - y) < 1e-12) return 0;
    if(x > y) return 1;
    return -1;
}
void dfs(double c, double m, double p, double last, int day)
{
	if(last * p < 1e-11 && day != 1) return;
	if(cmp(c, v) == 1){
		if(cmp(m, 0.0) == 1) dfs(c - v, m + v / 2, p + v / 2, last * c, day + 1);
		else dfs(c - v, m, p + v, last * c, day + 1);
	}
	else if(cmp(c, 0.0) == 0);
	else{
		if(cmp(m, 0.0) == 1) dfs(0, m + c / 2, p + c / 2, last * c, day + 1);
		else dfs(0, 0, p + c, last * c, day + 1);
	}
	
	
	if(cmp(m, v) == 1){
		if(cmp(c, 0.0) == 1) dfs(c + v / 2, m - v, p + v / 2, last * m, day + 1);
		else dfs(0, m - v, p + v, last * m, day + 1);
	}
	else if(cmp(m, 0.0) == 0);
	else{
		if(cmp(c, 0.0) == 1)dfs(c + m / 2, 0, p + m / 2, last * m, day + 1);
		else dfs(0, 0, p + m, last * m, day + 1);
	}
	ans += last * day * p;
}
int n, k;
signed main()
{
//    IOS;
    int t;
    cin >> t;
    while(t--)
    {
    	ans = 0;
        double c, m, p;
        cin >> c >> m >> p >> v;
        dfs(c, m, p, 1, 1);
        printf("%.6f\n", ans);
    }
    return 0;
}

D1. RPD and Rap Sheet (Easy Version)

题意

有一个密码 p p p,范围在 [ 0 , n ) [0,n) [0,n),每次可以询问一个数 x x x,然后会返回结果告诉你对了没有(0错,1对).

如果错了,那么密码会被修改为 x ⊕ p x⊕p xp(二进制异或). 你最多可以询问 n n n次.

分析

给一个序列 a [ i ] = i ⊕ ( i − 1 ) a[i]=i⊕(i-1) a[i]=i(i1),然后让 p p p与序列元素连续作和,得到:
p ⊕ 0 ⊕ 1 ⊕ 1 ⊕ 2 ⊕ 2 ⊕ . . . ⊕ ( i − 1 ) ⊕ i . p⊕0⊕1⊕1⊕2⊕2⊕...⊕(i-1)⊕i. p01122...(i1)i.
由于异或和满足结合律,故将其中相同的两两结合,最后得到 p ⊕ i p⊕i pi.

由于 p ∈ [ 0 , n ) p\in [0,n) p[0,n),必定存在一个 i = p − 1 i=p-1 i=p1,于是在与第 p − 1 p-1 p1项作异或后, p p p变为 p ⊕ ( p − 1 ) p⊕(p-1) p(p1);而 a [ p ] = p ⊕ p − 1 a[p]=p⊕p-1 a[p]=pp1,因此下一次必定猜到这个数. 故最多猜 p + 1 p+1 p+1次,也即最多猜 n n n次.

代码

#include <bits/stdc++.h>
#define fors(i, a, b) for(int i = (a); i <= (b); ++i)
#define lson k<<1
#define rson k<<1|1
#define pb push_back
#define lowbit(x) ((x)&(-(x)))
#define mem(a) memset(a, 0, sizeof(a))
#define IOS ios::sync_with_stdio(false), cin.tie(0)
#define int long long
const int inf = 0x3f3f3f3f;
const double dinf = 1e100;
typedef long long ll;
//const ll linf = 9223372036854775807LL;
// const ll linf = 1e18;
using namespace std;

signed main()
{
	IOS;
	int t;
	cin >> t;
	while(t--)
	{
		int n, k;
		cin >> n >> k;
		cout << 0 << endl;
		int x;
		cin >> x;
		if(x == 1) continue;
		fors(i, 1, n - 1)
		{
			cout << (i ^ (i - 1)) << endl;
			cin >> x;
			if(x == 1) break;
		}
	}
	return 0;
}
  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值