Codeforces Raif Round 1 (Div. 1 + Div. 2)

A

#include <bits/stdc++.h>
#define all(n) (n).begin(), (n).end()
#define se second
#define fi first
#define pb push_back
#define mp make_pair
#define sqr(n) (n)*(n)
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<ll, ll> PLL;
typedef vector<int> VI;
typedef double db;
 
template<class T1, class T2> bool umin(T1& a, T2 b) { return a > b ? (a = b, true) : false; }
template<class T1, class T2> bool umax(T1& a, T2 b) { return a < b ? (a = b, true) : false; }
template<class T> void clear(T& a) { T().swap(a); }
 
const int N = 2e5 + 5;
 
int n, m, _, k;
ll a[N], b[N];
 
int main() {
    IOS;
    for (cin >> _; _; --_) {
        ll a, b, x, y; cin >> a >> b >> x >> y;
        ll ans = abs(x - a) + abs(y - b) + 2;
        if (x == a || y == b) ans -= 2;
        cout << ans << '\n'; 
    } 
    return 0;
}

B

char s[N];
 
int main() {
    IOS;
    for (cin >> _; _; --_) {
        cin >> n >> s + 1;
        int a = 0;
        unordered_set<int> st;
        rep (i, 1, n) {
            if (s[i] == '-') st.insert(i % n), st.insert((i + 1) % n);
            else if (s[i] == '>') {
                if (a == 0) a = 1;
                else if (a == 2) a = -1;
            } else {
                if (a == 0) a = 2;
                else if (a == 1) a = -1;
            }
        }
        if (a != -1) cout << n << '\n';
        else cout << st.size() << '\n';
    }
    return 0;
}

C

贪心模拟

int main() {
    IOS;
    for (cin >> _; _; --_) {
        string s; cin >> s;
        int x = 0, y = 0, ans = 0;
        bool f = 0;
        for (auto c : s) {
            if (c == 'A') {
                if (f && y) ++x, y = 0, f = 0;
                ++x;
            }
            else if (c == 'B') {
                if (x) --x, ++ans, f = 1;
                else {
                    ++y;
                    if (y == 2) ++ans, y = 0;
                }
            }
        }
        cout << s.size() - (ans << 1) << '\n';
    } 
    return 0;
}

D

考虑到后效性, 倒着放, 同时对于行, 也是从 n 到 1, 把后效性消掉

我用的set只是为了图形优美, 什么容器都可

int a[N];
VI ans[N];
set<PII> st;
set<int> t;
 
int main() {
    IOS; cin >> n; int res = 0; m = n;
    rep(i, 1, n) cin >> a[i];
    bool f = 1;
    per(i, n, 1) {
        if (a[i] == 0) continue;
        if (a[i] == 1) ans[i].pb(m), ++res, st.insert({ m--, i });
        else if (a[i] == 2) {
            if (st.empty()) { f = 0; break; }
            PII ls = *st.rbegin();
            ans[i].pb(ls.fi); ++res;
            st.erase(ls); t.insert(i);
        }
        else {
            if (st.empty() && t.empty()) { f = 0; break; }
            if (!t.empty()) {
                int ls = *t.begin();
                ans[i].pb(m); ++res;
                ans[ls].pb(m--); ++res;
                t.erase(ls); t.insert(i);
            }
            else {
                PII ls = *st.rbegin();
                ans[i].pb(m); ++res;
                ans[ls.se].pb(m--); ++res;
                st.erase(ls); t.insert(i);
            }
        }
    }
    if (!f || m < 0 || res > 2 * n) { cout << -1; return 0; }
    cout << res << '\n';
    rep(i, 1, n) for (auto j : ans[i]) cout << j - k << ' ' << i << '\n';
    return 0;
}

E

优先队列

注意到, 将一个胡萝卜分的快数越多, 花费的时间越少, 就发现是优先队列, 每次选取 多分出一块 省的时间最多的那一根胡萝卜就行

ll a[N], b[N];

ll get(int x, int k) {
	if (a[x] < k) return 1e9;
	ll siz = a[x] / k, res = a[x] % k;
	return sqr(siz + 1) * res + sqr(siz) * (k - res);  
}

int main() {
    IOS; cin >> n >> k;
	priority_queue<PLI> q;
	rep (i, 1, n) {
		cin >> a[i], b[i] = 1;
		q.push({ get(i, 1) - get(i, 2), i });
	}
	rep (i, n + 1, k) {
		int x = q.top().se; q.pop();
		++b[x]; q.push({ get(x, b[x]) - get(x, b[x] + 1), x });
	}
	ll ans = 0;
	rep (i, 1, n) ans += get(i, b[i]);
	cout << ans;
    return 0;
}

F

//下标从1开始

dp(线段树也可), 常数大的O(n)

g[i] 表示 j~i (1 <= j <= i) 对答案的贡献, 那么最后的答案就是 \(\sum g[i]\)

明显 s[i] == '0', g[i] == g[i - 1],

对于 s[i] == '1', 讨论要复杂一些

因为是考虑区间最长的 '1', 理所应当我们要存个 t[i], 表示以 i 结尾的最长 '1', 毕竟在遍历 i 的时候, 区间最长 '1' 是会变的

显然 if s[i] == '0', t[i] = 0; else t[i] = t[i-1] + 1

当从 i - 1 到 i 的时候最后一段 '1' 变长了(s[i] == '1') 也就是说, 在上一段最后 t[i]个字符 到 (i - 1) - t[i - 1] 原本最长段是 t[i - 1](t[i - 1] == t[i] - 1)

然而现在成了 t[i], 也就说在这个区间内 多贡献了个区间长度, 对于 i-t[i]~i 也是多贡献了个区间长度

设 f[i] 表示 上一个长度为 i 的 '1' 串的起始位置, "1101" 在对于第4个位置的时候, 当前 '1' 段为 [4,4], 那么上一个 长度为 1 的段 是 [2, 2], 长度为2的段时[1, 2], 故 f[1] = 2, f[2] = 2

那么 s[i] == '1' 转移就已经出来了 g[i] = g[i + 1] + (i - t[i] - f[t[i]]) + t[i];

那么现在的问题成了怎么求 f[i], 显然 f[i] 对于 '1' 段是倒着的, "111110", 对于6位置 f[1] = 5, f[2] = 2, f[3] = 3, f[4] = 4, f[5] = 5;

其实已经发现了 f[i] = 上一个串的长度 - 正着数的位置, 比如对于 位置 i,

f[length(包含i的最长 '1' 的长度) - t[i] + 1] = i

至于长度嘛, 预处理O(n), 就行了, 虽然我用的并查集, 但还是O(1)的合并, 直接和 '1' 段的起始坐标最为祖先

然后我们又发现个问题, f[i] 随着 i 更新, 但我们计算 g[i] 的时候是想要未更新之前的 f[i], 如果先转移完, 在取跟新 f[i], 那必定超时(每遇到一个 '1' 串, 你都要重新遍历一遍)

所以每个位置存两个 f[i] 就好了, 当前的和上一个的, 通过下标判断, 应该取哪个和更新哪个

这样 f[i] 我们也有了

总的复杂度 O(n), 常数可能有点大, 并查集这里直接是O(1)

#include <bits/stdc++.h>
#define all(n) (n).begin(), (n).end()
#define se second
#define fi first
#define pb push_back
#define mp make_pair
#define sqr(n) (n)*(n)
#define rep(i,a,b) for(int i=(a);i<=(b);++i)
#define per(i,a,b) for(int i=(a);i>=(b);--i)
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr)
using namespace std;
typedef unsigned long long ull;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
typedef pair<ll, ll> PLL;
typedef pair<ll, int> PLI;
typedef vector<int> VI;
typedef double db;

template<class T1, class T2> bool umin(T1& a, T2 b) { return a > b ? (a = b, true) : false; }
template<class T1, class T2> bool umax(T1& a, T2 b) { return a < b ? (a = b, true) : false; }
template<class T> void clear(T& a) { T().swap(a); }

const int N = 5e5 + 5;

int n, m, _, k;
int fa[N], siz[N];
ll g[N], t[N];
PII f[N];
char s[N];

int find(int x) {
	return x == fa[x] ? x : fa[x] = find(fa[x]);
}

void unit(int x, int y) {
	x = find(x); fa[y] = x; siz[x] += siz[y];
}

int get(int x, int k) {
	if (f[k] == PII{ 0, 0 }) return 0;
	if (f[k].se > f[k].fi) swap(f[k].fi, f[k].se);
	if (fa[f[k].fi] != fa[x]) return f[k].fi;
	return f[k].se;
}

void change(int x, int k) {
	if (f[k].fi == 0) f[k].fi = x;
	else if (f[k].se == 0) f[k].se = x;
	else if (f[k].fi > f[k].se) f[k].se = x;
	else f[k].fi = x;
}

int main() {
	IOS; cin >> n >> s + 1;
	rep(i, 1, n) fa[i] = i;
	rep(i, 1, n)
		if (s[i] == '1') {
			t[i] = t[i - 1] + 1; siz[i] = 1;
			if (s[i - 1] == '1') unit(i - 1, i);
		}

	rep(i, 1, n) {
		if (s[i] == '0') g[i] = g[i - 1];
		else {
			g[i] = g[i - 1] + i - t[i] - get(i, t[i]) + t[i];
			int a = siz[find(i)]; change(i, a - t[i] + 1);
		}
	}
	ll ans = 0;
	rep(i, 1, n) ans += g[i];
	cout << ans;
	return 0;
}
posted @ 2020-10-18 12:30  洛绫璃  阅读(359)  评论(0编辑  收藏  举报