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

康复训练.jpg

A.Exciting Bets

题意

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

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

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

分析

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

代码

#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=1n∑j=i+1n∣ai−aj∣\sum_{i=1}^n \sum_{j=i+1}^n|a_i-a_j|i=1nj=i+1naiaj最小.

分析

假设数组的总和是sumsumsum.

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

很容易知道x=sum−avr⋅nx=sum-avr·nx=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,PC,M,PC,M,P,随机从他们中取一个,被取到的概率分别为c,m,pc,m,pc,m,p. 你的目标是取到PPP. 另外,还有一个小数vvvvvv是这样起作用的:

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

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

若抽xxx次抽到了PPP,问xxx的期望.

分析

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

注意

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

代码

#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)

题意

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

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

分析

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

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

代码

#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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值