[Codeforces] Round #775 (div 2)
A. Game
题意
给出一串只包含0或1的序列,遇到0时必须跳过,两个相邻1之间可以不消耗费用进行移动,至多只能跳一次,从i跳到i + x会产生费用x,求最小费用
思路
因为只能跳一次,所以必须要把所有0的位置都跳过
从离起点能到达的最远的1开始跳,跳到离终点最远的1的位置
如111001010100111,我们就从i=3跳到i=13的位置
用两次while循环找一下跳跃的起点终点即可
代码
#include<bits/stdc++.h>
#include <iostream>
#include <ctime>
using namespace std;
//==========================================
const int maxn = 1e5+5;
int a[maxn];
signed main(signed argc, char const *argv[])
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
#ifdef LOCAL
freopen("in.in", "r", stdin);
freopen("out.out", "w", stdout);
#endif
//======================================
int T;
cin >> T;
while(T --) {
int n;
cin >> n;
for(int i = 1; i <= n; i ++) {
cin >> a[i];
}
int flag = 0, fg = 0;
int ans = 0;
while(n) {
if(a[n] != 1) break;
n --;
}
int l = 1;
while(l) {
if(a[l] != 1) break;
l ++;
}
if(n == 0) {
cout << 0 << endl;
}
else cout << n - l + 2 << endl;
}
//======================================
return 0;
}
/*DETAILS
*/
B. Game of Ball Passing
题意
给定一个序列a,a[i]代表每个人传球的次数,求最少需要多少个球
可以从任意人开始传球,传到任意人(不包括自己)
思路
这题昨天卡了巨久,我真是太菜了
首先考虑全是0的情况,没有人需要传球,所以只需要0个球
再考虑一般情况
对于一个人传球,如果球传回自己手上,相当于消耗了某人和自己的一次传球次数
我们想要每次将传球次数最多的人的次数减少,所以最后必定只剩下一个人的传球次数
如果他的传球次数剩1,那么只需一个球即可
否则就需要maxn - (sum - maxn)个球
代码
void solve() {
int n;
cin >> n;
ll sum = 0, maxn = 0;
for(int i = 1; i <= n; i ++) {
cin >> a[i];
sum += a[i];
maxn = max(maxn, a[i]);
}
if(maxn == 0) {
cout << 0 << endl;
return;
}
sum -= maxn;
if(maxn > sum) cout << maxn - sum << endl;
else cout << 1 << endl;
}
C. Weird Sum
题意
求矩阵中所有相同颜色块对之间的曼哈顿距离
思路
对于曼哈顿距离:d(i, j)=|xi - xj| + |yi - yj|
就是两点间y轴差+x轴差
题目要我们求所有相同颜色块对之间的曼哈顿距离,暴力求肯定是不行的
考虑每个对之间会产生一个xi, xj, yi, yj
可以将其对所有相同颜色分行列进行合并求解
对于列,每新增一个相同颜色时,会对之前的这个颜色的总数都产生一个yj,总值是前面的总数乘yj,再减去前面的yi总和
对于行同理
代码
#include<bits/stdc++.h>
#include <iostream>
#include <ctime>
using namespace std;
//==========================================
const int maxn = 1e5+5;
typedef long long ll;
vector<int> col[maxn], row[maxn];
ll cal(vector<int> &color) {
sort(color.begin(), color.end());
ll pre = 0, res = 0, now = 0;
for(auto j : color) {
res += now * j - pre;//每次增加的值为列数*列值 - 列值总和
//(相当于把曼哈顿距离整体化,对于每个点对的距离都会产生一个j,再减掉之前加过的j即可)
now ++; //now维护当前颜色的列数量
pre += j; //pre维护当前列值总和
}
return res;
}
signed main(signed argc, char const *argv[])
{
ios::sync_with_stdio(false);
cin.tie(nullptr);
#ifdef LOCAL
freopen("in.in", "r", stdin);
freopen("out.out", "w", stdout);
#endif
//======================================
int n, m;
cin >> n >> m;
int x;
for(int i = 1; i <= n; i ++) {
for(int j = 1; j <= m; j ++) {
cin >> x;
col[x].push_back(j);
row[x].push_back(i);
}
}
ll ans = 0;
for(int i = 1; i <= 100000; i ++) {
ans += cal(col[i]) + cal(row[i]);
}
cout << ans << endl;
//======================================
return 0;
}
/*DETAILS
相同颜色的曼哈顿距离总和
*/
D. Integral Array
题意
给定n个数,对于每个x和y(x >= y),都要有x/y在这n个数中出现
思路
枚举每个y的倍数,相当于转换成x = y * k,如果有x和y出现,那么必然需要有k出现,否则就输出"NO"
对于每个x,y的范围是[y * k, y * k + y - 1],才满足x = y * k,用前缀和来确定这个区间内有没有数字即可
代码
void solve(){
int n, c;
cin >> n >> c;
for(int i = 1; i <= c * 2 + 10; i ++) {
cnt[i] = 0, ct[i] = 0;
}
int x;
for(int i = 1; i <= n; i ++) {
cin >> x;
if(!cnt[x]) cnt[x] ++, ct[x] ++;
}
for(int i = 1; i <= 2 * c + 10; i ++) {
cnt[i] += cnt[i - 1];
}
bool flag = false;
for(int i = 1; i <= c; i ++) {
if(ct[i]) {
for(int j = 1; j <= c / i; j ++) {
if(cnt[j * i + i - 1] - cnt[j * i - 1]) {
if(!ct[j]) {
flag = true;
break;
}
}
}
}
}
if(flag) {
cout << "NO" << endl;
}
else cout << "YES" << endl;
}

浙公网安备 33010602011771号