Codeforces#744(Div3)
今天要补2场CF的题目,算做给队友的生日礼物。
A. Casimir’s String Solitaire
SumA+SumC==SumB?“Yes”:“No”;
#include <bits/stdc++.h>
using namespace std;
int main() {
int T;
cin >> T;
while (T--) {
string s;
cin >> s;
int s1 = 0, s2 = 0;
for (int i = 0; i < s.length(); i++) {
if (s[i] == 'B') s1++;
else s2++;
}
if (s1 == s2)
cout << "YES" << endl;
else cout << "No" << endl;
}
}
B. Shifting Sort
洗牌题,意思是通过多次
l
r
d
lrd
lrd的洗牌,实现整个序列非递减。
l
r
d
lrd
lrd:意思是
[
l
,
r
]
[l,r]
[l,r]区间内长度为
d
d
d的部分向左循环变序。
模拟即可。
#include <bits/stdc++.h>
using namespace std;
int l[100], r[100], d[100];
int a[100], b[100];
int main() {
int T;
scanf("%d", &T);
while (T--) {
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
b[i] = a[i];
}
int cnt = 0;
sort(b + 1, b + 1 + n);
int p = 0;
for (int i = 1; i <= n; i++) {
p = 0;
for (int j = i; j <= n; j++) {
if (a[j] == b[i]) {
for (int k = j; k > i; k--) {
a[k] = a[k - 1];
}
p = j;
break;
}
}
if (p != i)
l[++cnt] = i, r[cnt] = p, d[cnt] = p - i;
}
printf("%d\n", cnt);
for (int i = 1; i <= cnt; i++)
printf("%d %d %d\n", l[i], r[i], d[i]);
}
}
C. Ticks
问你能不能把V连完,没有多出来的*。
我不太会写搜索,经常写裂,所以写了个循环,反正过了。
#include <bits/stdc++.h>
using namespace std;
string a[100];
int main() {
int T;
cin >> T;
while (T--) {
int n, m, k;
cin >> n >> m >> k;
for (int i = 0; i < n; i++)
cin >> a[i];
int d;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++) {
d = 0;
if (a[i][j] == '.') continue;
while (a[i - d - 1][j + d + 1] != '.' && a[i - d - 1][j - d - 1] != '.'
&& d < i && d < j && j + d + 1 < m)
d++;
if (d >= k) {
for (int sn = 0; sn <= d; sn++) {
a[i - sn][j - sn] = 'Q';
a[i - sn][j + sn] = 'Q';
}
}
}
int f = 0;
for (int i = 0; i < n; i++)
for (int j = 0; j < m; j++)
if (a[i][j] == '*') {
f = 1;
break;
}
if (f) cout << "No\n";
else cout << "Yes\n";
}
}
D.Productive Meeting
优先队列每次选最大2个(-1),贪心放回去,直到剩余非零元素为0或者为1。
#include <bits/stdc++.h>
using namespace std;
int main() {
int T;
scanf("%d", &T);
while (T--) {
priority_queue<pair<int, int>> q;
vector<pair<int, int>> ans;
int n;
scanf("%d", &n);
int t;
for (int i = 0; i < n; i++) {
scanf("%d", &t);
if (t)
q.push({t, i});
}
pair<int, int> a, b;
while (!q.empty()&&q.size()!=1) {
a = q.top();
q.pop();
b = q.top();
q.pop();
ans.push_back({a.second, b.second});
a.first--;
b.first--;
if (a.first) q.push(a);
if (b.first) q.push(b);
}
printf("%d\n", int(ans.size()));
for (int i = 0; i < ans.size(); i++)
printf("%d %d\n", ans[i].first+1, ans[i].second+1);
}
}
E1. Permutation Minimization by Deque
贴代码吧,过了快一万人了。
#include <bits/stdc++.h>
using namespace std;
int main() {
int T;
scanf("%d", &T);
while (T--) {
deque<int> q;
int n;
scanf("%d", &n);
int t;
for (int i = 1; i <= n; i++) {
scanf("%d", &t);
if (q.empty()) {
q.push_front(t);
} else if (t < q.front()) {
q.push_front(t);
} else {
q.push_back(t);
}
}
while (!q.empty()) {
printf("%d ", q.front());
q.pop_front();
}
printf("\n");
}
}
E2. Array Optimization by Deque
贪心题,贪心策略就是把一个数字放前面还是放后面,使得序列最终逆序对最少,那就都放放看,对每个元素取最优即可。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 10;
int a[maxn], tr[maxn];
int n;
ll lowbit(int x) {
return x & -x;
}
void add(int x, int y) {
while (x <= n) {
tr[x] += y;
x += lowbit(x);
}
}
ll getsum(int x) {
ll sum = 0;
while (x) {
sum += tr[x];
x -= lowbit(x);
}
return sum;
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
memset(tr, 0ll, sizeof(tr));
vector<ll> v;
for (int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
v.push_back(a[i]);
}
sort(v.begin(), v.end());
v.erase(unique(v.begin(), v.end()), v.end());
for (int i = 1; i <= n; i++) {
a[i] = lower_bound(v.begin(), v.end(), a[i]) - v.begin() + 1;
}
ll ans = 0;
for (int i = 1; i <= n; i++) {
ll h = getsum(a[i] - 1), t = getsum(n) - getsum(a[i]);
if (h <= t) ans += h;
else ans += t;
add(a[i], 1);
}
printf("%lld\n", ans);
}
}
重温树状数组:
我们假设一个数组
a
[
n
]
=
0
a[n]=0
a[n]=0时表示数字
n
n
n在序列中没有出现过,
a
[
n
]
=
1
a[n]=1
a[n]=1表示数字
n
n
n在序列中出现过。
a
a
a对应的树状数组为
t
r
[
n
]
tr[n]
tr[n],则
t
r
[
n
]
tr[n]
tr[n]对应维护的是数组
a
[
n
]
a[n]
a[n]的内容,可用于求
a
a
a中某个区间的值的和。
树状数组的插入函数的含义:
void add(int x, int y) {
while (x <= n) {
tr[x] += y;
x += lowbit(x);
}
}
在求逆序数这个问题中,我们的add函数通常使用为
i
n
s
e
r
t
(
i
,
1
)
insert( i , 1 )
insert(i,1),即将数组a[i]的值加1 (A数组开始应该初始化为0,所以也可以理解为设置a[ i ]的值为1,即将数字i 加入到序列的意思 )。
同时维护
t
r
tr
tr数组的值。
树状数组中区间求和函数含义:
ll getsum(int x) {
ll sum = 0;
while (x) {
sum += tr[x];
x -= lowbit(x);
}
return sum;
}
该函数的作用是用于求序列中小于等于数字 i 的元素的个数。序列中比元素a大的数的个数,可以用 g e t s u m ( n ) − g e t s u m ( a ) getsum(n) - getsum(a) getsum(n)−getsum(a)即可( i 表示此时序列中元素的个数)。
首先来看如何减小问题的规模:
要想求一个序列
a
b
c
d
a b c d
abcd,的逆序数的个数,可以理解为先求出
a
b
c
a b c
abc的逆序数的个数
k
1
k1
k1,再在这个序列后面增加一个数
d
d
d,求d之前的那个序列中值小于d的元素的个数k2,则
k
1
+
k
2
k1+k2
k1+k2即为序列
a
b
c
d
a b c d
abcd的逆序数的个数。
所以本题进行一个 a n s ans ans的加。
F. Array Stabilization (AND version)
@bcj记得写题解!!
G. Minimal Coverage
队友的博客
我之后再补。