Codeforces Round 920 (Div. 3)
A - Square
难度: ⭐
题目大意
给定正方形的四个顶点, 求该正方形的面积;
解题思路
根据四个点找出长和宽即可, 因为数据范围有负数, 为了方便我都进行了移位;
神秘代码
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, mod = 998244353;
typedef pair<int, int> PII;
signed main() {
int t;
cin >> t;
while(t--){
int a = 0, b = 0, l, r;
for(int i = 1; i <= 4; i++){
int x, y;
cin >> x >> y;
if(!a) a = x + 10000;
else if(x + 10000 != a) l = abs(a - x - 10000);
if(!b) b = y + 10000;
else if(y + 10000 != b) r = abs(b - y - 10000);
}
cout << l * r << endl;
}
return 0;
}
B - Arranging Cats
难度: ⭐⭐
题目大意
给定两个由01组成的字符串S1, S2; 可以对S1进行三种操作: 把1变成0; 把0变成1; 把某个1和某个0互换位置;
请问最少进行多少次操作可以让其转变成S2;
解题思路
分析三种操作可以发现肯定是优先进行第三种操作; 设两个字符串有x个位置数字不同, 这其中有a个S1是1, b个S2是1 (b = x - a); 我们可以用这a个1转移到那b个1的位置, 少了就再加, 多了就删去; 最终发现操作次数就是a和b中的最大值;
神秘代码
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, mod = 998244353;
typedef pair<int, int> PII;
int n, m;
signed main() {
int t;
cin >> t;
while(t--){
cin >> n;
string s1, s2;
cin >> s1 >> s2;
int a = 0, b = 0;
for(int i = 0; i < n; i++){
if(s1[i] != s2[i]){
if(s1[i] == '1') a++;
else if(s2[i] == '1') b++;
}
}
cout << max(a, b) << endl;
}
return 0;
}
C - Sending Messages
难度: ⭐⭐
题目大意
小莫的手机在时刻0还有m格电量; 小莫需要在n个不同时刻给安姐发消息; 手机亮屏x时间消耗a * x格电量, 小莫还可以选择息屏, 到该发消息时再亮屏; 息屏需要b格电量, 息屏期间不耗电; 默认发信息时不耗电; 请问小莫是否可以用m格电路坚持发完最后一个消息; 注意如果x时刻需要发信息, 但是x时刻刚好没电, 那么消息就发不出去;
解题思路
一开始以为是个dp, 结果发现想多了, 只需要贪心就行; 对于每两个时刻之间的间隔, 分析是亮屏还是息屏更优;
神秘代码
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, mod = 998244353;
typedef pair<int, int> PII;
int n, m;
int p[N];
signed main() {
int t;
cin >> t;
while(t--){
int a, b, res = 0;
cin >> n >> m >> a >> b;
for(int i = 1; i <= n; i++){
cin >> p[i];
if(a * (p[i] - p[i - 1]) >= b){
res += b;
}
else res += a * (p[i] - p[i - 1]);
}
if(res < m) cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}
D - Very Different Array
难度: ⭐⭐⭐
题目大意
安姐有一个n个数的数组A, 小莫有一个m个数的数组B; 小莫想从中选出n个数并且排列成数组C, 使得$\Sigma$|Ai - Ci|最大
解题思路
因为是求和, 所以数组A的顺序也就无所谓了; 题意也就变成找出n对(Ai, Ci), 使得$\Sigma$|Ai - Ci|最大; 这就有两种情况, 是Ai - Ci (Ai大)还是Ci - Ai (Ci大), 这里我们需要找出此时A中的最大值和最小值以及C中的最大值和最小值, 带入进去试一试看谁的差值大就选谁, 然后把那两个数去掉再找下一对即可, 有点贪心的意思; 找的过程可以用双指针;
神秘代码
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, mod = 998244353;
typedef pair<int, int> PII;
int n, m;
int a[N], b[N];
signed main() {
int t;
cin >> t;
while(t--){
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 1; i <= m; i++) cin >> b[i];
sort(a + 1, a + 1 + n);
sort(b + 1, b + 1 + m);
int al = 1, bl = 1, ar = n, br = m;
int res = 0;
for(int i = 1; i <= n; i++){
int x = a[ar] - b[bl];;
int y = b[br] - a[al];
if(x > y){
res += x;
ar--, bl++;
}
else{
res += y;
br--, al++;
}
}
cout << res << endl;
}
return 0;
}
E - Eat the Chip
难度: ⭐⭐⭐
题目大意
给定一个n * m的网格, 小莫和安姐各持一枚棋子, 小莫的棋子只能从上往下走, 而安姐只能从下往上走; 两者具体的移动方式就是往自己的正前方或左前方或右前方前进一格; 如果某人的棋子正好落在对方的棋子上, 那么他就赢了; 给定两枚棋子的初始位置, 判断谁会赢; 如果最后小莫走到了最下面一行, 而安姐走到了最上面一行, 那么算平局; 小莫先走;
解题思路
当两人还面对着时, 每走一次都会缩小两人之间的间距; 所以我们可以根据初始间距判断两人到横坐标相同时各需要行动多少次; 然后算出这两人在这一横坐标下所能覆盖的纵坐标范围有多大, 如果其中某个人可以覆盖掉对方的范围, 并且此时还是他的回合, 那么他就必胜; 至于此时是谁的回合也是用初始横坐标间距来算;
神秘代码
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e6 + 10, mod = 998244353;
typedef pair<int, int> PII;
int n, m;
int a[N], b[N];
signed main() {
int t;
cin >> t;
while(t--){
int h, w, xa, ya, xb, yb;
cin >> h >> w >> xa >> ya >> xb >> yb;
int hl = xb - xa - 1, wl = abs(yb - ya) - 1;
if(hl < 0) cout << "Draw" << endl;
else if(hl % 2){
int la = max(1ll, ya - hl / 2 - 1);
int ra = min(w, ya + hl / 2 + 1);
int lb = max(1ll, yb - hl / 2 - 1);
int rb = min(w, yb + hl / 2 + 1);
if(lb <= la && rb >= ra){
cout << "Bob" << endl;
}
else cout << "Draw" << endl;
}
else {
int la = max(1ll, ya - hl / 2 - 1);
int ra = min(w, ya + hl / 2 + 1);
int lb = max(1ll, yb - hl / 2);
int rb = min(w, yb + hl / 2);
if(la <= lb && ra >= rb){
cout << "Alice" << endl;
}
else cout << "Draw" << endl;
}
}
return 0;
}
F - Sum of Progression
难度: ⭐⭐⭐⭐
题目大意
给定一个长度为n的数组ai, 现在有m组询问, 每组询问有s, d, k三个属性, 表示从as往后数k个数的和, 步长为d, 且第i个数要乘i; 即res = as + 2 * as+d + 3 * as+2d ... (k - 1) * as+kd;
解题思路
本题需要用到根号分治的方法; 对于d >= sqrt(n)时, 那么最多也就有sqrt(n)个数, 直接打暴力就行; 所以我们只需要考虑d < sqrt(n)的情况; 对于res的形式我们发现越靠后乘的数越大, 所以可以考虑用后缀和(r)的形式, 对后缀和取后缀和(rs)就可以得到类似于题目要求的形式; rsi就相当于ai + 2 * ai+1 + 3 * ai+2 ... + (n - i + 1) * an; 但是又要考虑到步长, 所以rs和r都要设为二维, 根据不同步长来计算后缀和和后缀和的后缀和; 根据rs的形式就可以推算出答案, ress k d = rss d - rss+k*d d - k * rs+k*d d
神秘代码
#include<bits/stdc++.h>
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#define endl '\n'
using namespace std;
const int N = 1e5 + 500, mod = 1e9 + 7;
typedef pair<int, int> PII;
int n, m;
int p[N];
int dp[N][400], f[N][400];
signed main() {
IOS;
int t;
cin >> t;
while(t--){
cin >> n >> m;
int sq = sqrt(n);
for(int i = 1; i <= sq; i++){
for(int j = 1; j <= n; j++){
f[j][i] = 0;
dp[j][i] = 0;
}
}
for(int i = 1; i <= n; i++){
cin >> p[i];
}
for(int i = 1; i <= sq; i++){
for(int j = n; j >= 1; j--){
f[j][i] = f[j + i][i] + p[j];
dp[j][i] = dp[j + i][i] + f[j][i];
}
}
while(m--){
int s, d, k;
cin >> s >> d >> k;
int res = 0;
if(d > sq || k <= sq){
for(int i = 1; i <= k; i++){
res += i * p[s + (i - 1) * d];
}
}
else{
res = dp[s][d] - dp[s + k * d][d] - k * f[s + k * d][d];
}
cout << res << ' ';
}
puts("");
}
return 0;
}