Codeforces Round 1017 (Div. 4) A~F
Codeforces Round 1017 (Div. 4) A~F
A. Trippi Troppi
题意&思路
- 输出每个字符串的第一个数字
代码
#include <iostream>
#include <string>
#define endl '\n'
using namespace std;
void solve() {
string s1, s2, s3;
cin >> s1 >> s2 >> s3;
cout << s1[0] << s2[0] << s3[0] << endl;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int _; cin >> _;
while (_--) {
solve();
}
return 0;
}
B. Bobritto Bandito
题意
- 从0点开始感染,每次感染左边或者右边的,最终感染的区间是[l,r]
思路
- 当前是第n个状态,要找到第m个状态,也就是要倒退n-m天,那就是被感染的房子数量要减少n-m个
- 我是先让右边倒退(题意应该是每次感染左右都是随机的,所以顺序无所谓),右边最多可以倒退r次(到了0之后就不能再倒退了)
- 也就是右边最多取消感染r个房子,那就看r和n-m的关系,如果r>n-m,那就只要处理右边,否则剩下的(n-m)-r天,留给左边处理
代码
#include <iostream>
#define endl '\n'
using namespace std;
void solve() {
int n, m, l, r;
cin >> n >> m >> l >> r;
int ri = min(n - m, r);
if (ri == r) {
l += ((n - m) - ri);
}
cout << l << " " << r - ri << endl;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int _; cin >> _;
while (_--) {
solve();
}
return 0;
}
C. Brr Brrr Patapim
题意
- 给一个二维数组,然后根据二维数组求一个序列
- 二维数组里面的Gi,j代表了序列里第 i+j 个数字
思路
- 序列就是从1到2n每个数字出现一次,二维数组会告诉i+j位置的数字,i+j的范围是[2,2n]
- 所以就是序列的第一个数字没有告诉,其他位置的数字都告诉了,那么就搞一个vis数组,标记从1到2n,里面哪个数字出现了,哪个数字没有出现,没有出现那个就是第一个位置的数字
- 具体就是先处理二维数组里的数字,填到序列数组的对应位置,输出的时候先输出第一个位置的数字,然后再从第二个位置开始输出序列数组
代码
#include <iostream>
#include <cstring>
#include <vector>
#define endl '\n'
using namespace std;
int map[805][805];
int vis[805];
void solve() {
memset(map, 0, sizeof(map));
memset(vis, 0, sizeof(vis));
int n; cin >> n;
vector<int>v(2*n+5);
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> v[i + j];
vis[v[i + j]] = 1;
}
}
for (int i = 1; i <= 2 * n; i++) {
if (!vis[i]) {
cout << i << " ";
break;
}
}
for (int i = 2; i <= 2 * n; i++) {
cout << v[i] << " ";
}
cout << endl;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int _; cin >> _;
while (_--) {
solve();
}
return 0;
}
D. Tung Tung Sahur
题意
- 给定两个字符串p、s,都只包含LR,p中的L跟R被敲击一次,可能出现一个L,也可能出现两个L(R同样),就问根据p这个敲击顺序,可不可能听到s这样的声音
思路
- 记录p和s中,L和R每个连续段的长度,让L和R的每个段对应上(前提是p和s的第一个字符要一样),假设p上每一段连续段的L(或者R)数量是i,那p这一段可能产生的声音就是 [i,2*i]个 L(或者R),如果s中对应那一段的数量,不在这个范围,那就不对
代码
#include <iostream>
#include <vector>
#include <string>
#include <algorithm>
#define endl '\n'
using namespace std;
vector<int>ans;
void solve() {
string p, s; cin >> p >> s;
if (p[0] != s[0]) {
ans.push_back(0);
return;
}
vector<int>vp, vs;
int cnt = 1;
for (int i = 1; i < p.length(); i++) {
if (p[i - 1] == p[i]) {
cnt++;
}
else {
vp.push_back(cnt);
cnt = 1;
}
}
vp.push_back(cnt);
cnt = 1;
for (int i = 1; i < s.length(); i++) {
if (s[i - 1] == s[i]) {
cnt++;
}
else {
vs.push_back(cnt);
cnt = 1;
}
}
vs.push_back(cnt);
// 对应不上
if (vp.size() != vs.size()) {
ans.push_back(0);
return;
}
// 可以打印看一下
//for (auto x : vp) {
// cout << x << " ";
//}
//cout << endl;
//for (auto x : vs) {
// cout << x << " ";
//}
//cout << endl;
for (int i = 0; i < vs.size(); i++) {
if (vp[i] * 2 < vs[i] || vp[i] > vs[i]) {
ans.push_back(0);
return;
}
}
ans.push_back(1);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int _; cin >> _;
while (_--) {
solve();
}
for (auto x : ans) {
cout << ((x) ? "YES" : "NO") << endl;
}
return 0;
}
E. Boneca Ambalabu
题意
- 给一个数组,然后每次拿出其中一个ak,求 (ak⊕a1)+(ak⊕a2)+…+(ak⊕an) ,找到最大的结果
思路
- 第一次写这种肯定很容易就可以想到枚举k,然后再计算n次得到结果,但就是O(n2)会超时
- 所以就想异或的计算,如果取出来的 ak 的第 j个位置是0,取出每一个ai的第j个位置要是1,这时候才产生贡献,因为异或是(不进位相加)嘛,所以可以这时候可以不用枚举ai,可以提前算出这n个数字里面,第j个位置是1的有多少个,把计算这一位的时间从O(n)变成O(1)了,那就不会超时,如果取出来的 ak 的第 j个位置是1,也同理,其他数字对应位置是0的数量就是n-对应位置是1的数量
- 贡献计算是把枚举的ak按位拆开,逐位看贡献
代码
#include <iostream>
#include <vector>
#include <algorithm>
#define endl '\n'
using namespace std;
vector<long long>ans;
int n;
void solve() {
cin >> n;
vector<int>cnt(31, 0); // 每一位上1出现的次数
vector<long long>a(n + 1);
for (int i = 1; i <= n; i++) {
cin >> a[i];
for (int j = 0; j < 31; j++) {
if ((a[i] >> j) & 1) { // 把第j个位置的数移到最后一位,和1与运算
cnt[j]++;
}
}
}
long long res = 0, sum = 0;
for (int k = 1; k <= n; k++) { // 枚举ak,外面是O(n)
sum = 0;
for (int j = 0; j < 31; j++) { // 枚举位置
if ((a[k] >> j) & 1) { // 是1,那就看对应位置是0的数量
sum += 1ll * (n - cnt[j]) * (1ll << j);
}
else {
sum += 1ll * cnt[j] * (1ll << j);
}
}
res = max(res, sum);
}
ans.push_back(res);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int _; cin >> _;
while (_--) {
solve();
}
for (auto x : ans) {
cout << x << endl;
}
return 0;
}
F. Trulimero Trulicina
题意
- 给n*m的网格,把1,2,3,4...... k ,每个数字都填入相同的次数
思路
-
一开始试一下把1,2,3,4...... k,1,2,3,4...... k,....... 按顺序填进去
样例那个3 4 6 就变成
1 2 3
4 5 6
1 2 3
4 5 6
发现符合题意,那就可以按照这样构造
num从0开始,每次输出num % k + 1,然后num++,就可以有这样的效果
-
但是第一个样例2 2 2 会变成
1 2
1 2
因为这时候m%k==0了,
看个大一点的样例3 4 4
1 2 3 4
1 2 3 4
1 2 3 4
或者k≠m的:3 4 2
1 2 1 2
1 2 1 2
1 2 1 2
发现每一行会跟上面或者下面的数字相同,所以要试一下错位,在每一行开始的时候,让num先+1,感觉可以理解为,第一行的num从1开始,第二行的num从2开始……
代码
#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
#define endl '\n'
using namespace std;
int n, m, k;
void solve() {
cin >> n >> m >> k;
bool flag = false;
if (m % k == 0)flag = true;
int num = 0;
for (int i = 1; i <= n; i++) {
if (flag)num++;
for (int j = 1; j <= m; j++) {
cout << (num++ % k + 1) << " ";
}
cout << endl;
}
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
int _; cin >> _;
while (_--) {
solve();
}
return 0;
}

浙公网安备 33010602011771号