今天要补2场CF的题目,算做给队友的生日礼物。
比赛传送门
A. Casimir’s String SolitaireSumA+SumC==SumB?“Yes”:“No”;
#includeB. Shifting Sortusing 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; } }
洗牌题,意思是通过多次
l
r
d
lrd
lrd的洗牌,实现整个序列非递减。
l
r
d
lrd
lrd:意思是
[
l
,
r
]
[l,r]
[l,r]区间内长度为
d
d
d的部分向左循环变序。
模拟即可。
#includeC. Ticksusing 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("%dn", cnt); for (int i = 1; i <= cnt; i++) printf("%d %d %dn", l[i], r[i], d[i]); } }
问你能不能把V连完,没有多出来的*。
我不太会写搜索,经常写裂,所以写了个循环,反正过了。
#includeD.Productive Meetingusing 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 << "Non"; else cout << "Yesn"; } }
优先队列每次选最大2个(-1),贪心放回去,直到剩余非零元素为0或者为1。
#includeE1. Permutation Minimization by Dequeusing namespace std; int main() { int T; scanf("%d", &T); while (T--) { priority_queue > q; vector > 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 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("%dn", int(ans.size())); for (int i = 0; i < ans.size(); i++) printf("%d %dn", ans[i].first+1, ans[i].second+1); } }
贴代码吧,过了快一万人了。
#includeE2. Array Optimization by Dequeusing namespace std; int main() { int T; scanf("%d", &T); while (T--) { deque 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"); } }
贪心题,贪心策略就是把一个数字放前面还是放后面,使得序列最终逆序对最少,那就都放放看,对每个元素取最优即可。
#include重温树状数组: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 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("%lldn", 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队友的博客
我之后再补。



