康复训练.jpg
A.Exciting Bets
题意
给出两个数a,ba,ba,b,每次操作可以:
- a++;
- 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,a−b),由于a−ba-ba−b不变,找到离aaa最近的a−ba-ba−b的倍数即可.
代码
#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=1n∑j=i+1n∣ai−aj∣最小.
分析
假设数组的总和是sumsumsum.
贪心,确保∣aj−ai∣|a_j-a_i|∣aj−ai∣尽量小,只要让整个数组所有数都尽量接近平均数即可。对平均数向下取整得到avravravr,则假设有xxx个数能修改成avravravr,那么剩下的n−xn-xn−x个数就是avr+1avr+1avr+1,这个时候的所求结果就是x⋅(n−x)x · (n-x)x⋅(n−x),一定为最小。
很容易知道x=sum−avr⋅nx=sum-avr·nx=sum−avr⋅n.
代码
/**
* @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. 另外,还有一个小数vvv,vvv是这样起作用的:
- 如果取到了PPP,直接结束.
- 如果取到了A≠PA \neq PA=P,且0<a≤v0 < a \leq v0<a≤v,那么aaa变为0,且状态变为不可用,剩下的可用物品将概率aaa平分(例如剩下2个都可用,那么每个都加上a2a \over 22a;如果只有一个可用,就让它加上aaa)
- 如果a>va>va>v,那么aaa变为a−va-va−v,剩下的可用物品将概率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·aN⋅a; 选到ppp时,答案加上N⋅p⋅当前递归抽的次数N·p·当前递归抽的次数N⋅p⋅当前递归抽的次数. 最后输出答案,注意一下精度即可。当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⊕px⊕p(二进制异或). 你最多可以询问nnn次.
分析
给一个序列a[i]=i⊕(i−1)a[i]=i⊕(i-1)a[i]=i⊕(i−1),然后让ppp与序列元素连续作和,得到:
p⊕0⊕1⊕1⊕2⊕2⊕...⊕(i−1)⊕i.
p⊕0⊕1⊕1⊕2⊕2⊕...⊕(i-1)⊕i.
p⊕0⊕1⊕1⊕2⊕2⊕...⊕(i−1)⊕i.
由于异或和满足结合律,故将其中相同的两两结合,最后得到p⊕ip⊕ip⊕i.
由于p∈[0,n)p\in [0,n)p∈[0,n),必定存在一个i=p−1i=p-1i=p−1,于是在与第p−1p-1p−1项作异或后,ppp变为p⊕(p−1)p⊕(p-1)p⊕(p−1);而a[p]=p⊕p−1a[p]=p⊕p-1a[p]=p⊕p−1,因此下一次必定猜到这个数. 故最多猜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;
}