Codeforces Round #806 (Div. 4)
Codeforces Round #806 (Div. 4)
https://codeforces.com/contest/1703
抱歉啊。。鸽了这么久。实在是最近太懒惰了唉
A. YES or YES?
(看到题目的时候DNA动了,差点唱出来)
直接按题意判断即可
#include <bits/stdc++.h>
using namespace std;
bool check (string s) {
if (s[0] != 'Y' && s[0] != 'y') return false;
if (s[1] != 'E' && s[1] != 'e') return false;
if (s[2] != 'S' && s[2] != 's') return false;
return true;
}
void solve () {
string s;
cin >> s;
if (check (s))
cout << "YES\n";
else cout << "NO\n";
}
int main () {
int t; cin >> t;
while (t --) solve ();
}
B. ICPC Balloons
模拟
第一次出现的字母+2,后续每出现一次都+1
#include <bits/stdc++.h>
using namespace std;
void solve () {
int n, ans = 0;
string s;
cin >> n >> s;
set<char>se;
for (int i = 0; i < n; i ++) {
if (se.count(s[i])) ans ++;
else {
ans += 2;
se.insert (s[i]);
}
}
cout << ans << endl;
}
int main () {
int t; cin >> t;
while (t --) solve ();
}
C. Cypher
(我读题不细心,后面的输入不是字符串,而是按字符输入)
给出操作后的结果以及操作过程,求开始的过程
全反即可 (U变D,D变U)
取模法则:( + 10)% 10,保证其在0-9的范围内
#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int a[N];
void solve () {
int n; cin >> n;
for (int i = 1; i <= n; i ++) cin >> a[i];
for (int i = 1; i <= n; i ++) {
int x = a[i];
int m; cin >> m;
//string s; cin >> s;
int cnt = 0;
for (int j = 0; j < m; j ++) {
char ch; cin >> ch;
if (ch == 'U') cnt --;
else cnt ++;
}
cnt = (cnt+10)%10;
//cnt %= 10;
x += cnt, x = (x+10)%10;
cout << x << ' ';
}
cout << endl;
}
int main () {
int t; cin >> t;
while (t --) solve ();
}
//给出操作后的结果以及操作过程,求开始的过程
//全反即可
//超出%10
//挨个输入的
D. Double Strings
每次给n个串,如果该串能由 其它两串 或 一串重复两次 拼接而成,则为输出1,否则输出0
一开始想的暴力维护set,O(n^2)TLE了。
突破点在于串的长度很小,所以可以从开头结尾向中间枚举(前后缀)
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
string s[N];
int n, sz;
void solve () {
cin >> n;
set <string> se;
for (int i = 1; i <= n; i ++) cin >> s[i], se.insert (s[i]);
for (int i = 1; i <= n; i ++) {
bool suc = false;
for (int j = 1; j < s[i].size(); j ++) {
string x = s[i].substr (0, j), y = s[i].substr (j); //前后缀 0到j-1, j到sz-1
if (se.count (x) && se.count (y)) {
suc = true;
break;
}
}
if (suc) cout << 1;
else cout << 0;
}
cout << endl;
}
int main () {
int t; cin >> t;
while (t --) solve ();
}
//如果能被别的表示就是1
//n^2暴力 不行
//substr(st, len)
//因为长度小,所以可以从左右两端开始枚举
E. Mirror Grid
要求改变当前方阵,使得其顺时针翻转90°三次后的结果都重合。我的做法是多枚举几对翻转后重合的坐标,然后找规律,如图:
不难发现,一对坐标的规律就是:
(i,j)->(j,n-i+1)->(n-i+1,n-j+1)->(n-j+1,i)
注意for循环范围
#include <bits/stdc++.h>
using namespace std;
const int N = 105;
int n, g[N][N];
//string s[N];
void solve () {
int ans = 0;
cin >> n;
for (int i = 1; i <= n; i ++) {
string s; cin >> s;
for (int j = 0; j < n; j ++) {
g[i][j+1] = s[j] - '0';
}
}
//对角线
for (int i = 1; i <= n/2; i ++) {
for (int j = 1; j <= (n+1)/2; j ++) {
int a = g[i][j], b = g[j][n-i+1], c = g[n-i+1][n-j+1], d = g[n-j+1][i];
int cnt = a + b + c + d;
//if (cnt == 0 || cnt == 4) continue;
if (cnt == 1 || cnt == 3) ans ++;
if (cnt == 2) ans += 2;
}
}
cout << ans << endl;
}
int main () {
int t; cin >> t;
while (t --) solve ();
}
//四个行列都相等
//统计坐标关系
//找规律
F. Yet Another Problem About Pairs Satisfying an Inequality
找出满足\(a_i<i<a_j<j\)的(i,j)有多少对
直接把满足\(a_i<i\)的\(a_i\)和i放进两个vector里,然后lower_bound二分查找即可
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 2e5 + 5;
int a[N], n;
void solve () {
cin >> n;
vector <int> v1, v2;
for (int i = 1; i <= n; i ++) {
cin >> a[i];
if (a[i] < i) {
v1.push_back (a[i]), v2.push_back (i);
}
}
int ans = 0;
n = v1.size();
for (int i = 0; i < n; i ++) {
ans += lower_bound (v2.begin(), v2.end(), v1[i]) - v2.begin();
}
cout << ans << endl;
}
signed main () {
int t; cin >> t;
while (t --) solve ();
}
//a[i]<i<[j]<j
//先把不满足a[i]<i的踢掉
G. Good Key, Bad Key
有好钥匙和坏钥匙。一把好钥匙会花费k; 坏钥匙使用过后,其后的所有物品价值都会变为原来的1/2。
做法一:贪心
好钥匙放前面一定是最优的,因为他不会使得物品减少,
随后就只需要求出最大可能放多少把即可(从后向前枚举)
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N = 1e5 + 5;
int a[N], sum[N], n, k;
void solve () {
cin >> n >> k;
for (int i = 1; i <= n; i ++) {
cin >> a[i];
sum[i] = sum[i-1] + a[i];
}
vector <int> s1;
int ans = 0;
for (int i = n; i >= 0; i --) {
int cur = sum[i] - k * i;
for (auto j : s1)
cur += j;
ans = max (ans, cur);
s1.push_back (a[i]);
vector<int> s2;
for (auto j : s1) {
if (j > 1)
s2.push_back (j / 2);
}
swap (s1, s2);
}
cout << ans << endl;
}
signed main () {
int t; cin >> t;
while (t --) solve ();
}
//11110000
做法二:dp
预处理a[i][j]: a[i][j] = a[i][0] >> j;
dp[i][j]表示到第i个箱子为止,一共使用了j次坏钥匙的产生的最大贡献:
- 当前宝箱用坏钥匙开 dp[i−1][j−1]+a[i][j]
- 当前宝箱用好钥匙开 dp[i−1][j]+a[i-1][j]−k
int n, m;
int a[N];
LL dp[N][35];//开第i个盒子用了j个bad钥匙能obtain的maximum
int pow2[N];
void solve()
{
cin >> n >> m;
for (int i = 1; i <= n; i++) {
cin >> a[i][0];
dp[i][0] = 0;
for (int j = 0; j <= min(i, 30); j++) {
dp[i][j] = 0;
a[i][j] = a[i][0] >> j; // 预处理a[i][]
}
}
LL ans = 0;
for(int i = 1; i <= n; i ++ )
for(int j = 0; j <= 30; j ++ ){
if(j == 0) dp[i][j] = max(dp[i - 1][0] + a[i] - m, dp[i][j]);
else{
dp[i][j] = max({dp[i - 1][j - 1] + a[i] / pow2[j], dp[i - 1][j] + a[i] / pow2[j] - m});
}
ans = max(dp[i][j], ans);
}
printf("%lld\n",ans);
}
(感觉一个人多少有些自闭emm)