Codeforces Round #786 (Div. 3)
A. Number Transformation
原题:
题目大意:
给你一个x,y,问你能否对x通过乘以a次b可以得到y的方案,可以输出a和b即可(答案不唯一),如果不可以,输出0 0。
思路分析:
略
代码:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int t, a, b, x, y;
int main()
{
cin >> t;
while(t --){
cin >> x >> y;
if(y % x){
cout<<"0 0"<<'\n';
}
else{
cout<<"1 "<<y / x << "\n";
}
}
return 0;
}
B. Dictionary
原题:
题目大意:
根据题意对给定的字符串输出其对应的下标即可。
思路分析:
略
代码:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int t;
string tmp;
int main()
{
cin >> t;
while(t -- ){
cin>>tmp;
int ans = 0;
ans = (tmp[0] - 'a') * 25;
if(tmp[1] > tmp[0])ans += tmp[1] - 'a';
else ans += tmp[1] - 'a' + 1;
cout << ans << '\n';
}
return 0;
}
C. Infinite Replacement
原题:
题目大意:
给定一个字符串s和字符串t,字符串都是由a字符构成,我们通过t取替换s中字符a的地方,能够得到多少方案。如果会无限循环输出-1,反之输出方案即可。
思路分析:
分类讨论:
1)如果t = ‘a’; 那么就一种方案 1
2)如果t 中有’a’, 每次替换s的时候都会多一个a,会无限循环,那么就 - 1
3)如果t 中没有a, 就是每次替换s的方案数,即 2^len
代码:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int q;
string s, t;
long long jc(int n){
long long ans = 1;
for(int i = 1; i <= n; i ++)ans *= 2;
return ans;
}
int main()
{
cin >> q;
while(q --){
cin >> s;
cin >> t;
int flag = 0, len = t.size(), len2 = s.size();
for(int i = 0; i < len; i ++){
if(t[i] == 'a'){
flag = 1;
break;
}
}
if(t.size() == 1 && flag)cout<<"1"<<'\n';
else if(flag)cout<<"-1"<<'\n';
else {
long long ans = jc(len2);
cout << ans<< '\n';
}
}
return 0;
}
/*
1)如果t = a; 那么就一种方案 1
2)如果t 中有a, 那么就 - 1
3)如果t 中没有a, 那么就 2^len
*/
D. A-B-C Sort
原题:
题目大意:
先后对a数组和b数组进行操作,问能否使得得到的c是非递减的。
操作:
思路分析:
对a数组考虑,可以发现,最前面的数肯定是先被c取到放到最后面的数
如果要让最后的c数组是非递减的,必须满足:
如果初始a数组的长度n是偶数:t == 2;
如果初始a数组的长度n是奇数:t == 1;
1)t == 1时,下标idx数的大小要小于等于idx + 2和idx + 3
- t == 2时,下标idx数的大小要小于等于idx + 1和idx + 2
代码:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1e6 + 5;
int t, n;
int a[N];
int main()
{
cin >> t;
while(t --){
cin >> n;
for(int i = 1; i <= n; i ++)cin >> a[i];
int flag = 1, t = 1;
if(n % 2)t = 2;
for(int idx = 1; idx <= n; idx ++){
if(t == 1){
t = 2;
if(a[idx] > a[idx + 2] && idx + 2 <= n){
flag = 0;
break;
}
if(a[idx] > a[idx + 3] && idx + 3 <= n){
flag = 0;
break;
}
}
else if(t == 2){
t = 1;
if(a[idx] > a[idx + 1] && idx + 1 <= n){
flag = 0;
break;
}
if(a[idx] > a[idx + 2] && idx + 2 <= n){
flag = 0;
break;
}
}
}
if(flag)cout << "YES" << '\n';
else cout << "NO" << '\n';
}
return 0;
}
E. Breaking the Wall
原题:
题目大意:
有n面墙,问你摧毁任意两座(可以不相连)需要的最少操作数。
每一次操作:可以选择任意一座墙造成2点伤害,并且其左右相邻的墙同时收到1点伤害。
思路分析:
分类讨论一下:
1)攻击使相邻两个使两个摧毁:
最优:令两个墙中强度最小为minn,最大为maxx
再次讨论:
1、如果minn * 2 <= maxx
我们直接可以通过用2伤害攻击强大最大的墙,当最大的墙摧毁时,那么较小的那面墙也肯定摧毁了。
2、如果minn * 2 > maxx
用2伤害直接攻击最大强度的墙,肯定会达到两面墙强度相等的时候,然后依次轮流每次攻击一面墙,两面墙的差最多为1,让输出达到最大化,结果肯定能够同时到达0 或者 一个为0 一个为 1,后者就直接再攻击依次就好了。
for(int i = 1; i <= n - 1; i ++){
int maxx = -N, minn = N;
maxx = max(a[i], a[i + 1]);
minn = min(a[i], a[i + 1]);
if(minn * 2 <= maxx){
s1 = min(s1, (maxx + 1) / 2);
}
else{
s1 = min(s1, (a[i] + a[i + 1] + 2) / 3);
}
}
2)通过攻击中间一个摧毁其旁边两面墙:
最优:枚举所有情况,攻击中间一个墙,如果左右两边有一面墙强度为0了,就直接用2伤害去攻击另一边的墙, 取最小值。
for(int i = 1; i <= n - 2; i ++){
int tmp = min(a[i], a[i + 2]) + (abs(a[i + 2] - a[i]) + 1) / 2;
s2 = min(s2, tmp);
}
3)直接攻击摧毁两个不相邻的墙
最优情况就是找两个强度最小min1和min2的墙,让后分别通过两点伤害就他们摧毁即可。
(min1 + 1) / 2 + (min2 + 1) / 2
因为1) 2) 3 )就包含了所有情况,所以答案即取1) 2) 3)的最小值
代码:
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
const int N = 1e6 + 10;
int n, s1 = N, s2 = N, ans = N;
int a[N];
int main()
{
cin >> n;
for(int i = 1; i <= n; i ++)cin >> a[i];
for(int i = 1; i <= n - 1; i ++){
int maxx = -N, minn = N;
maxx = max(a[i], a[i + 1]);
minn = min(a[i], a[i + 1]);
if(minn * 2 <= maxx){
s1 = min(s1, (maxx + 1) / 2);
}
else{
s1 = min(s1, (a[i] + a[i + 1] + 2) / 3);
}
}
for(int i = 1; i <= n - 2; i ++){
int tmp = min(a[i], a[i + 2]) + (abs(a[i + 2] - a[i]) + 1) / 2;
s2 = min(s2, tmp);
}
sort(a + 1, a + n + 1);
ans = min({s1, s2, (a[1] + 1) / 2 + (a[2] + 1) / 2});
cout << ans << '\n';
return 0;
}
F. Desktop Rearrangement
原题:
题目大意:
加删图标,问排列整齐最少需要几步。
整齐:从左往右依次排数列,排满一列排下列。
思路分析:
分类讨论,维护不需要排的数量,答案就是总图标数减去不需要排的图标数。
代码:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <map>
using namespace std;
typedef pair<int, int> PII;
const int N = 1e3 + 5, M = 1e6 + 5;
int n, m, q, sum = 0;
char g[N][N];
map<PII, int>mp;
int main()
{
cin >> n >> m >> q;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j ++){
cin >> g[i][j];
if(g[i][j] == '*'){
sum ++;
mp[{i, j}] = 1;
}
}
}
//统计在范围内的点数
int cnt = 0;
for(int i = 1; i <= n; i ++){
for(int j = 1; j <= m; j ++){
if(mp[{i, j}] == 1 && (j - 1) * n + i <= sum)cnt ++;
}
}
//最大能排到的位置ii jj
int ii, jj;
if(sum % n == 0){
ii = n;
jj = sum / n;
}
else {
ii = sum % n;
jj = sum / n + 1;
}
//cout<<sum<<" "<<cnt<<'\n';
while(q --){
int x, y, tmp, ans;
cin >> x >> y;
tmp = n * (y - 1) + x;
// cout<<"tmp:"<<tmp<<" " << "sum:"<<sum<<" "<<"cnt:"<<cnt<<'\n';
// cout<<"mp:"<<mp[{x, y}]<<'\n';
if(tmp > sum && mp[{x, y}] == 1){
sum --;
mp[{x, y}] = 0;
if(mp[{ii, jj}] == 1)cnt --;
if(ii == 1){
ii = n;
jj --;
}
else{
ii --;
}
}
else if(tmp <= sum && mp[{x, y}] == 1){
sum --;
cnt --;
mp[{x, y}] = 0;
if(mp[{ii, jj}] == 1 && (x != ii || y != jj))cnt --;
if(ii == 1){
ii = n;
jj --;
}
else{
ii --;
}
}
else if(tmp <= sum && mp[{x, y}] == 0){
cnt ++; sum ++;mp[{x, y}] = 1;
if (ii == n){
ii = 1;
jj += 1;
}
else {
ii ++;
}
if(mp[{ii, jj}] == 1 )cnt++;
}
else if(tmp > sum && mp[{x, y}] == 0){
sum ++;mp[{x, y}] = 1;
if (ii == n){
ii = 1;
jj += 1;
}
else {
ii ++;
}
if(mp[{ii, jj}] == 1 )cnt++;
}
ans = sum - cnt;
cout << ans << '\n';
}
return 0;
}