题意分析: 有两排电脑, 每一排的电脑是左右互连的,现在要求你将上下两排的电脑连接起来, 形成容错网络: 即网络保持连接,尽管其中一台计算机出现故障。换句话说,如果一台计算机坏了(不管是哪台),网络就不会分裂成两个或多个部分。连接两台计算机的费用是 ∣ a i − b j ∣ |a_i - b_j| ∣ai−bj∣
首先形成容错网络, 连四条边 是肯定可以的, 但不一定是最优的, 也可以连两条边, 也可以连三条边
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define x first
#define y second
typedef pair<int,int>PII;
#define debug printf("debug\n");
const int N = 5e5 + 10, INF = 0x3f3f3f3f, mod = 998244353;
int t;
int a[N], b[N], n;
void solve()
{
cin >> n;
for(int i = 1; i <= n; i ++ ) cin >> a[i];
for(int i = 1; i <= n; i ++ ) cin >> b[i];
int v0 = INF, v1 = INF, v2 = INF, v3 = INF;
for(int i = 1; i <= n; i ++ )
v0 = min(v0, abs(a[1] - b[i])), //得到每一条边的最小值
v1 = min(v1, abs(a[n] - b[i])),
v2 = min(v2, abs(b[1] - a[i])),
v3 = min(v3, abs(b[n] - a[i]));
int ans = v0 + v1 + v2 + v3; //四条边
ans = min(ans, abs(a[1] - b[1]) + v1 + v3); //合并a1->bi b1->ai
ans = min(ans, abs(a[n] - b[n]) + v0 + v2); //合并ai->bn an->bi
ans = min(ans ,abs(a[1] - b[n]) + v1 + v2); //合并a1->bi bn->ai
ans = min(ans, abs(a[n] - b[1]) + v0 + v3); //合并ai->b1 an->bi
ans = min(ans, abs(a[1] - b[1]) + abs(a[n] - b[n])); //合并两条
ans = min(ans, abs(a[1] - b[n]) + abs(a[n] - b[1])); //合并两条
cout << ans << '\n';
}
signed main()
{
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> t;
while(t -- )solve();
}
题意分析: 给定长度 n n n, 存在一种操作使 a i = a j = ∣ a i − a j ∣ a_i = a_j = |a_i - a_j| ai=aj=∣ai−aj∣, 是否存在长度为 n n n 的序列能够在任意操作下总和不会变小
题意分析: 为了去掉绝对值我们可以考虑使序列元素的值从小到大, 这样对于任意的
i
,
j
i,j
i,j 我们只要保证从左往右扫一遍, 从右往左扫一遍, 符合要求即可
从左往右扫
a
i
+
a
j
≥
2
∗
(
a
j
−
a
i
)
a_i + a_j ≥ 2 * (a_j - a_i)
ai+aj≥2∗(aj−ai) 得到
3
∗
a
i
≥
a
j
3 * a_i ≥a_j
3∗ai≥aj
从右往左扫
a
i
+
a
j
≥
2
∗
(
a
i
−
a
j
)
a_i + a_j ≥ 2 * (a_i - a_j)
ai+aj≥2∗(ai−aj)
3
∗
a
j
≥
a
i
3 * a_j ≥ a_i
3∗aj≥ai
所以只要右边元素是左边元素的三倍即可, 然后因为
a
a
a 在
i
n
t
int
int 范围, 最大为
3
19
3^{19}
319, 所以
n
n
n 大于
19
19
19 都是不合法的
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define x first
#define y second
typedef pair<int,int>PII;
#define debug printf("debug\n");
const int N = 5e5 + 10, INF = 0x3f3f3f3f, mod = 998244353;
int t;
int pow2[100];
void solve()
{
int n;
cin >> n;
if(n > 19) //不合法
cout << "NO\n";
else
{
cout << "YES\n";
for(int i = 1; i <= n; i ++ ) //直接枚举咯
cout << pow2[i - 1] << " ";
cout << '\n';
}
}
signed main()
{
pow2[0] = 1; //预处理3的n次方
for(int i = 1; i <= 19; i ++ ) pow2[i] = pow2[i - 1] * 3;
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> t;
while(t -- )solve();
}
题意: 给定整数 n n n, 每位运动员上标有一个数字, 该数字的范围是 1 1 1 ~ 2 n 2^n 2n, 从小到大相邻的两个数为一组, 一组中将决出一个赢家, 然后晋级下一轮, 每轮决胜规则是 当一组中运动员的编号之和为奇数, 小的获胜, 和为偶数时, 大的获胜, 请你输出最后获胜者的编号
分析: 不难发现经过第一轮后,只剩下了编号为奇数的运动员, 所以剩下的比赛中和都为偶数, 所以获胜者都是编号大的, 故发现第一轮先取小, 后面全取大, 那就是 2 n − 1 2 ^ n - 1 2n−1
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define x first
#define y second
typedef pair<int,int>PII;
#define debug printf("debug\n");
const int N = 5e5 + 10, INF = 0x3f3f3f3f, mod = 998244353;
int t;
int pow2[100];
void solve()
{
int n;
cin >> n;
//n轮比赛
cout << pow2[n] - 1 << '\n';
}
signed main()
{
pow2[0] = 1; //预处理2的次幂
for(int i = 1; i <= 30; i ++ ) pow2[i] = pow2[i - 1] * 2;
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
cin >> t;
while(t -- )solve();
}
写作不易, 给个赞吧!