Educational Codeforces Round 96 (Rated for Div. 2) ABCEDF A B C D E F

暴力拼

int main(){
    IOS;
    for (cin >> _; _; --_) {
	cin >> n;
	bool f = false;
	rep (i, 0, n / 3) {
	    if (f) break;
	    rep (j, 0, n / 5)
		if ((n - i * 3 - j * 5) % 7 == 0) {
		    cout << i << ' ' << j << ' ' << (n - i * 3 - j * 5) / 7 << '
';
			f = true;
			break;
		}
	}
	if(!f) cout << -1 << '
';
    }
    return 0;
}

B

排序选就完了

int main() {
    IOS;
    for (cin >> _; _; --_) {
        cin >> n >> k; ++k;
        ll ans = 0;
        rep (i ,1, n) cin >> a[i];
        sort(a + 1, a + 1 + n);
        rep (i, 1, k) ans += a[n - i + 1];
        cout << ans << '
';
 
    } 
    return 0;
}

C

倒着输出完事, 必定为2

int main() {
    IOS;
    for (cin >> _; _; --_) {
        cin >> n; m = n; k = n - 1;
        cout << 2 << '
';
        rep (i, 2, n) {
            cout << k << ' ' << m << '
';
            m = (k + m + 1) / 2; --k;
        }
    } 
    return 0;
}

D

贪心, 统计0110101串个数 cnt

为 0 的时候 遇见连续的 0000 或 1111 你只能 +1

有 cnt 的时候 你就可以慢悠悠的 取 连续串, 取的时候留一个, 相当于又多了个 01

int main() {
    IOS;
    for (cin >> _; _; --_) {
        cin >> n >> s + 1;
        int ans = 0, c = 0;
        rep (i, 1, n) {
            int j = i;
            while (j + 1 <= n && s[j] == s[j + 1]) ++j;
            if (i == j) ++c;
            else {
                if (c >= j - i) ans += j - i, c -= j - i - 1;
                else ans += c + 1, c = 0;
                i = j;
            }
        }
        ans += c + 1 >> 1;
        cout << ans << '
';
    } 
    return 0;
}

E

求逆序对

看题目, 相邻交换, 最后有序, (逆序对即使交换的最少次数, 归并排序交换的次数)

int n, m, _, k;
char s[N];
int a[N], c[N];

void add(int x, int k) {
    for (; x <= n; x += -x & x) c[x] += k;
}

int ask(int x) {
    int ans = 0;
    for (; x; x -= -x & x) ans += c[x];
    return ans;
}

int main() {
    IOS; cin >> n >> s + 1;
    VI tax[27]; ll ans = 0;
    per(i, n, 1) tax[s[i] ^ 96].pb(n - i + 1);
    per(i, n, 1) a[i] = tax[s[i] ^ 96].back(), tax[s[i] ^ 96].pop_back();
    rep (i, 1, n) add(a[i], 1), ans += i - ask(a[i]);
    cout << ans;
    return 0;
}

F

没一眼看出来E是逆序对是真的....

一看提, 贪心的想把每波怪 在来之前最少需要多少f[i]子弹算出来

然而, 你算出来当前贪心最少需要多少子弹, 然后你当前打光了子弹, 下一波 f[i + 1] > 0 直接 gg

所以我们要考虑后效性, 倒着想, f[i] 表示 i ~ n 在第i波之前需要最少的子弹

这样就没后效性了, 求晚 f[i], 正着来一遍就好了

但是! 我们有 r[i] == l[i + 1] 的情况

我们能直接将 i 和 i + 1 合并吗? 显然不能(i + 1 波怪 可以在 r[i + 1]之前打完, i波不行)

但是 f[i + 1] 和 f[i] 可以啊, i 和 i + 1之间不能换弹, 所以 f[i]必须包含 f[i + 1] 的部分, 这样就处理完了

(你可以直接将 f[i] += f[i + 1], 在特判 -1, 也可以直接 a[i] += f[i + 1])

ll a[N], l[N], r[N], f[N];

int main() {
    IOS; cin >> n >> k;
    ll ans = 0, res = k;
    rep (i, 1, n) cin >> l[i] >> r[i] >> a[i];
    per (i, n, 1) {
        ll res = a[i];
        if (r[i] == l[i + 1]) res += f[i + 1];
        if (res > (r[i] - l[i] + 1) * k) { cout << -1; return 0; }
        f[i] = max(0ll, res - (r[i] - l[i]) * k);
    }
    rep (i, 1, n) {
        if (res < f[i]) ans += res, res = k;
        ans += a[i]; res = ((res - a[i]) % k + k) % k;
    }
    cout << ans;
    return 0;
}