Oct. Training 1 - G
G. Hacker, pack your bags!
https://codeforces.com/problemset/problem/822/C
题意
给定n组数\(li, ri, ci\)代表一个区间范围和该区间的花费,给一个k值,求选择两个不重叠区间的区间长度和为k且花费和最小。
思路
将每个区间放进对应长度的vector里,然后对vector按区间左边界排序,从后遍历求后缀花费最小值,
再遍历每个区间为选择的第一个区间,长度为len,然后在k-len的vector中二分查找第二个区间,如果找得到,加上的花费就是恰好包含第二个区间的后缀最小值。每次答案取min。
#include<bits/stdc++.h>
#include<unordered_map>
#include<array>
#define ll long long
#define ull unsigned long long
#define all(a) a.begin(),a.end()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-8;
const ll mod = 19650827;
const int N = 2e5 + 5;
const int maxn = 1e5 + 10;
ll n, m;
pair<pair<int, int>, int>p[N];
vector<pair<pair<int, int>, int>>ve[N];
map<pair<int, int>, int>mi;
void solve()
{
cin >> n >> m;
int l, r;
ll v;
for (int i = 1; i <= n; i++) {
cin >> l >> r >> v;
p[i] = { make_pair(l, r), v };
ve[r - l + 1].push_back(p[i]);
}
//排序 求后缀最小值
for (int i = 1; i <= 2e5; i++){
sort(ve[i].begin(), ve[i].end());
int mii = inf;
for (int j = ve[i].size() - 1; j >= 0; j--) {
mii = min(mii, ve[i][j].second);
mi[{i, j}] = mii;
}
}
int ans = 2e9 + 1;
for (int i = 1; i <= n; i++) {
int l = p[i].first.first;
int r = p[i].first.second;
int len = m - (r - l + 1);
if (len <= 0 || !ve[len].size()) continue;
int L = 0, R = ve[len].size() - 1, pos = -1;
//二分找第一个不重叠的区间
while (L <= R) {
int mid = (L + R) / 2;
if (mid >= ve[len].size()) break;
if (ve[len][mid].first.first > r) {
pos = mid;
R = mid - 1;
}
else L = mid + 1;
}
//int pos = upper_bound(ve[len].begin(), ve[len].end(), r) - ve[len].begin();
if (pos < 0) continue;
ans = min(ans, p[i].second + mi[{len, pos}]);
}
if (ans == 2e9+1) cout << -1 << "\n";
else cout << ans << "\n";
}
signed main()
{
IOS;
int _t = 1;
//cin >> _t;
while (_t--)
solve();
return 0;
}
F - Balance the Bits
https://codeforces.com/problemset/problem/1504/C
题意
给出一个01串 0代表可变 1代表不可变,问能否构造出一个包含'('和')'的字符串,在0位置的字符改变前后都满足括号匹配原则。
思路
容易想到的一点是左右两端必须是1 否则无解,且左右两端分别是'('和')'。
如果是奇数个1,也无法构造出来。
我们先不看1,就看0, 按'('、')'依次排列,即'()()()'的形式,然后将它们改变后就是')()()('的形式,因为左右两边一定由一个左括号和右括号,所以改变后也合法。
那么0的合法了,对于1,我们加上几对固定的'()'也一定合法,所以对于1,我们也只要按'('、')'依次构造即可。
#include<bits/stdc++.h>
#include<unordered_map>
#include<array>
#define ll long long
#define ull unsigned long long
#define all(a) a.begin(),a.end()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-8;
const ll mod = 19650827;
const int N = 2e5 + 5;
const int maxn = 1e5 + 10;
ll n, m;
char a[N], b[N];
string s;
void solve()
{
cin >> n;
cin >> s;
s = ' ' + s;
ll sum = 0;
a[1] = '(';
a[n] = ')';
int cnt0 = 0, cnt1 = 0;
for (int i = 2; i < n; i++) {
if (s[i] == '0') cnt0++;
if (s[i] == '1') cnt1++;
if (s[i] == '0' && cnt0 % 2) a[i] = '(';
else if (s[i] == '1' && cnt1 % 2) a[i] = '(';
else a[i] = ')';
}
if (s[1] == '0' || s[n] == '0' || cnt1 % 2) {
cout << "NO\n";
return;
}
for (int i = 1; i <= n; i++) {
if (s[i] == '1') b[i] = a[i];
else {
b[i] = (a[i] == ')' ? '(' : ')');
}
}
int x = 0;
for (int i = 1; i <= n; i++) {
if (b[i] == '(') x++;
else x--;
if (x < 0) {
cout << "NO\n";
return;
}
}
if (x != 0) {
cout << "NO\n";
return;
}
cout << "YES\n";
for (int i = 1; i <= n; i++) cout << a[i];
cout << "\n";
for (int i = 1; i <= n; i++) cout << b[i];
cout << "\n";
}
signed main()
{
IOS;
int _t = 1;
cin >> _t;
while (_t--)
solve();
return 0;
}
E. Little Artem and Time Machine
https://codeforces.com/problemset/problem/669/E
题意
有三种操作:
1 \(t_i\) \(x_i\) 在\(t_i\)秒将\(x_i\)加入到集合中去
2 \(t_i\) \(x_i\) 在\(t_i\)秒将\(x_i\)从集合中删去(保证存在)
3 \(t_i\) \(x_i\) 询问第\(t_i\)秒集合中有几个\(x_i\)
顺序给出n次操作,后面操作对前面操作不影响,即便时间可能早于前面操作
对于每次操作3 输出一个值
思路
先将操作3都放入一个vector中,并按时间排序。
然后按操作循序一次遍历操作,如果某次操作时间晚于当前的操作3 就放入优先队列中(按时间从小到大),等到时间到了再弹出来操作,否则直接操作。
如果遍历到某个操作3 如果该操作3已经有答案就直接conitnue
不然就依次弹出队列中早于该操作的的操作,加给答案。如果当前操作3是当前按vector遍历到的vector,我们就向后遍历下一个操作3,否则将答案记录后将队列复原。
#include<bits/stdc++.h>
#include<unordered_map>
#include<array>
#define ll long long
#define ull unsigned long long
#define all(a) a.begin(),a.end()
#define IOS ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
using namespace std;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const double eps = 1e-8;
const ll mod = 19650827;
const int N = 2e5 + 5;
const int maxn = 1e5 + 10;
ll n, m;
pair<pair<ll, ll>, int>p[N];
map<ll, int>cnt;
int vis[N], ans[N];
void solve()
{
cin >> n;
int op;
ll t, x;
vector<pair<ll, int>>ve;
for (int i = 1; i <= n; i++) {
cin >> op >> t >> x;
p[i] = { {t, x}, op };
if (op == 3) ve.push_back({ t, i });
}
sort(ve.begin(), ve.end());
priority_queue < pair<pair<ll, ll>, int>, vector<pair<pair<ll, ll>, int>> , greater<pair<pair<ll, ll>, int>> >q;
int pre = 0;
for (int i = 1; i <= n; i++) {
while (vis[ve[pre].second]) pre++;
ll now = ve[pre].first;
while (!q.empty() && q.top().first.first < now) {
int op = q.top().second;
int x = q.top().first.second;
op == 1 ? cnt[x]++ : cnt[x]--;
q.pop();
}
ll t = p[i].first.first;
ll x = p[i].first.second;
ll op = p[i].second;
if (op == 3) {
int num = cnt[x];
vector<pair<pair<ll, ll>, int > >res;
while (!q.empty() && q.top().first.first < t) {
int op = q.top().second;
int xx = q.top().first.second;
if(xx == x)
op == 1 ? num++ : num--;
q.pop();
}
//队列复原
for (auto x : res) q.push(x);
ans[i] = num;
vis[i] = 1;
continue;
}
if (t > now) {
q.push(p[i]);
continue;
}
op == 1 ? cnt[x]++ : cnt[x]--;
}
for (int i = 1; i <= n; i++) {
if (p[i].second == 3) {
cout << ans[i] << "\n";
}
}
}
signed main()
{
IOS;
int _t = 1;
//cin >> _t;
while (_t--)
solve();
return 0;
}