Codeforces Round #710 (Div. 3)
Codeforces Round #710 (Div. 3)
https://codeforces.com/contest/1506
昨天的vp
A. Strange Table
计算坐标,然后转化
#include <bits/stdc++.h>
#define int long long
using namespace std;
void solve () {
int n, m, z;
cin >> n >> m >> z;
// if (n * m == z) {
// cout << z << endl;
// return;
// }
int y = ceil(1.0*z/n), x = z%n;
if (x == 0) x = n;
//cout << x << ' ' << y << endl;
cout << (x-1)*m+y << endl;
}
signed main () {
int t;
cin >> t;
while (t --) {
solve ();
}
}
//坐标
//(ceil(x/m),x%m)
B. Partial Replacement
我是直接模拟填距离
似乎也可以dp,改天学习一下
#include <bits/stdc++.h>
#define int long long
using namespace std;
void solve () {
int n, k;
string s;
cin >> n >> k >> s;
vector <int> v; //坐标
for (int i = 0; i < n; i ++) {
if (s[i] == '*') v.push_back (i);
}
int m = v.size ();
if (m <= 2) {
cout << m << endl;
return ;
}
// for (auto i : v) cout << i << ' ';
// cout << endl;
int ans = 2;
int len = 0;
for (int i = 1; i < m; i ++) {
len += v[i] - v[i-1];
//cout << "len=" << len << endl;
if (len == k && i != m-1) ans ++, len = 0;
else if (len > k) i --, len = 0, ans ++;
//len += v[i] - v[i-1];
}
cout << ans << endl;
}
//两个x之间的坐标差<=k
signed main () {
int t;
cin >> t;
while (t --) {
solve ();
}
}
C. Double-ended Strings
找到最长相等连续子串,长度为len
答案为n+m-len*2
做法:拿小的在大的上面偏移,匹配最长长度
暴力,注意细节
因为细节疯狂WA
#include <bits/stdc++.h>
using namespace std;
void solve () {
string a, b;
cin >> a >> b;
if (a == b) {
cout << "0\n";
return ;
}
int n = a.size (), m = b.size ();
if (n < m) swap (n, m), swap (a, b);
//cout << n << ' ' << m << endl;
int ans = 0;
for (int i = 0; i < n; i ++) {
int len = 0;
for (int j = 0; j < m; j ++) {
if (b[j] != a[i]) {
ans = max (ans, len);
len = 0;
continue;
}
//cout << "len=" << len << endl;
len ++;
while (i+len<n && j+len<m && b[j+len] == a[i+len]) len++;
ans = max (ans, len);
len = 0;
}
}
//cout << ans << endl;
cout << n + m - ans * 2 << endl;
}
int main () {
int t;
cin >> t;
while (t --) {
solve ();
}
}
//删前或后
//字符串匹配
//找到最长相等连续子串,长度为len
//答案为n+m-len*2
//case4:
// dhjak jsnasjhfks afasd
// ad jsnasjhfks vdafdser
// jsnasjhfks
//复杂度n^2
//拿小的在大的上面偏移,匹配最长长度
D. Epic Transformation
每次可以删两个不一样的
最少剩下几个
具体处理:用堆
每次拿两个不同的出来--
要对数量敏感啊!!这种大小关系的就要想到STL
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii; //数量,种类
const int N = 2e5 + 5;
int a[N];
void solve () {
map<int, int> mp;
int n;
cin >> n;
for (int i = 0; i < n; i ++)
cin >> a[i], mp[a[i]] ++;
sort (a, a + n);
priority_queue <pii> q; //默认降序
for (int i = 1; i < n; i ++) {
if (a[i] != a[i-1])
q.push ({mp[a[i-1]], a[i-1]});
}
q.push ({mp[a[n-1]], a[n-1]}); //别忘了最后一个也要放上
while (!q.empty ()) {
auto a = q.top();
q.pop();
if (q.empty ()) {
q.push (a);
break;
}
auto b = q.top();
q.pop();
a.first --, b.first --; //配对
if (a.first) q.push (a);
if (b.first) q.push (b);
}
if (q.empty ()) cout << "0\n";
else cout << q.top().first << endl;
}
int main () {
int t;
cin >> t;
while (t --) {
solve ();
}
}
//每次可以删两个不一样的
//最少剩下几个
//具体处理:用堆
//每次拿两个不同的出来--
//说白了还是stl不熟练
E. Restoring the Permutation
set维护可放的数字 + 二分查找
(还是STL不熟
#include <bits/stdc++.h>
#define IOS ios::sync_with_stdio (0);cin.tie(0);
using namespace std;
const int N = 2e5 + 5;
int n;
// void test () {
// for (int i = 1; i <= n; i ++) cout << b1[i] << ' ';cout << endl;
// for (int i = 1; i <= n; i ++) cout << vis1[i] << ' ';cout << endl;
// }
void solve () {
cin >> n;
set<int> s1, s2;
deque <int> a(n+1), b1(n+1), b2(n+1);
for (int i = 1; i <= n; i ++) {
cin >> a[i], s1.insert (i), s2.insert (i); //默认递增
}
for (int i = 1; i <= n; i ++) {
if (a[i] != a[i-1]) {
b1[i] = b2[i] = a[i];
s1.erase (a[i]), s2.erase (a[i]);
}
else {
//min
b1[i] = *(s1.begin());
s1.erase (b1[i]);
//max
auto it = s2.lower_bound (a[i]); //大于等于
it --; //第一个大于等于他的上一个(就是最大小于他的)
b2[i] = *it;
s2.erase (b2[i]);
}
}
b1.pop_front(), b2.pop_front (); //首项是0
for (auto i : b1) cout << i << ' '; cout << endl;
for (auto i : b2) cout << i << ' '; cout << endl;
}
int main () {
int t;
cin >> t;
while (t --) solve ();
}
//每一段的首项固定
//暴力TLE
//优化:用集合来维护
//min: s.begin()为答案
//max: lower_bound()找到小于a[i]的最大元素
F. Triangular Paths
有一个 n 行的下三角矩阵
当 (i+j) % 2 == 0 时 (i, j) 有一条通往 (i + 1, j) 的边,否则 (i, j) 有一条通往 (i + 1, j + 1) 的边
可以花费 1 的代价令某一个点的出边在抵达 (i + 1, j)和 (i + 1, j + 1)之间互换
找规律:
(x-y)%2 为奇时,往右下走cost不变;否则cost++
迭代更新
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
const int N = 200010;
int n;
pii e[N];
void solve () {
cin >> n;
for(int i = 1; i <= n; i ++) cin >> e[i].first;
for(int i = 1; i <= n; i ++) cin >> e[i].second;
e[0] = {1, 1};
sort(e + 1, e + n + 1);
int res = 0;
for(int i = 1; i <= n; i ++) {
int dx = e[i].first - e[i - 1].first, dy = e[i].second - e[i - 1].second;
int t = dx - dy;
if (t == 0) {
if((e[i].first - e[i].second) % 2 == 0) res += dx;
}
else {
if((e[i - 1].first - e[i - 1].second) % 2) res += (t + 1) / 2; //上取整
else res += t / 2;
}
}
cout << res << endl;
}
int main() {
int t; cin >> t;
while (t --) solve ();
}
G. Maximize the Remaining String
去重的基础上+单调栈
pos[]:记录每一个字母在序列中出现的最后位置
(括号太多。。。绕晕了。。检查了半天。。。麻)
#include <bits/stdc++.h>
using namespace std;
typedef pair<char, int> pci; //字符,下标
const int N = 2e5 + 5;
bool vis[28];
int pos[28];
void solve () {
memset (vis, false, sizeof vis);
memset (pos, 0, sizeof pos);
string s;
cin >> s;
int n = s.size ();
for (int i = 0; i < n; i ++) pos[s[i] - 'a'] = i;
//构造单调栈
stack<int> stk;
for (int i = 0; i < n; i ++) {
if (vis[s[i] - 'a']) continue;
while (!stk.empty () && s[i] > s[stk.top ()] && i < pos[s[stk.top ()] - 'a'])
vis[s[stk.top()] - 'a'] = false, stk.pop(); //不能能塞进去的踢出去
stk.push (i), vis[s[i] - 'a'] = true;
}
//反向输出
vector <char> v;
while (!stk.empty ()) v.push_back (s[stk.top()]), stk.pop ();
reverse (v.begin (), v.end ());
for (auto i : v) cout << i; cout << endl;
}
int main () {
int t;
cin >> t;
while (t --) solve ();
}
//删掉相同的字符
//相同的一前s[i]一后s[j],比较s[i]与s[i+1],s[j]与s[j+1]
//如果s[i]<s[i+1],删s[i]
//如果s[i]>s[i+1],删s[j]
//如果s[i]==s[i+1](即j==i+1),删谁都行
//策略没问题,关键是不会操作
//没过去的点:
//abacaba
//me:bca
//jd:cba
//先交一发假做法
//正确做法:单调栈