[CF1076F] Summer Practice Report

Description

Transmission Gate

Solution

这一题可以考虑Dp,设(Dp[i][j]) 为在第i段中,以j颜色为结尾的最后一小段长度的最小值。

那么可以先考虑以表为结尾的情况:

  1. 表上一个线段的结尾,就把表看作分隔符,那么分隔符的数量下界是$lowerBound = lceil frac{(Dp[i - 1][j] + a[i])}{k} ceil - 1 (, 如果`b[i] > cnt`, 那么)dp[i][j] = 1(,上界)upperBound$是a[i] * k

  2. 表是上一个线段的结尾, 分隔符数量下界是(lowerBound = lceil frac{a[i]}{k} ceil - 1), 上界 $upperBound $ 是 (a[i] * k + (k - Dp[i - 1][j ~ xor ~ 1]))

    最后判断(dp[n][0] leq k || dp[n][1] leq k)

Summary

​ 刚开始设状态(dp[i][j][l]) 表示dp到ith段,段的最后颜色为j,这样的颜色在这一段的最后一部分有l长是否有解。 其实这样是不对的,算方案数判断是否可行的套路只适用于一些容斥数学题(eg. Mobius), 所以就多上一维的冗余信息。

​ 问题的模型是: 我们有n个段,段之间首尾相连,要求段中间的连续的隔板与球不超过k个。求是否有解。这样,我们不关心内部的排列方式, 并且内部排列不同不会影响下一段。这样的话我们可以直接考虑外部限制的情况下,钦定一种内部可行的方式。 而钦定就是对简单贪心的考察。

​ 因为上一段的影响对下一段越小,对解的限制也就越小(越容易出解),所以可以直接贪心。

​ 先考虑公式,将无关的公式看做挡板,表看作球。然后直接尽量容纳表即可。

Code

#include<bits/stdc++.h>
using std :: min;
#define rep(i, a, b) for(int i = (a), i##_end_ = (b); i <= i##_end_; ++i)
#define drep(i, a, b) for(int i = (a), i##_end_ = (b); i >= i##_end_; --i)
#define clar(a, b) memset((a), (b), sizeof(a))
#define debug(...) fprintf(stderr, __VA_ARGS__)
typedef long long LL;
typedef long double LD;
int read() {
    char ch = getchar();
    int x = 0, flag = 1;
    for (;!isdigit(ch); ch = getchar()) if (ch == '-') flag *= -1;
    for (;isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
    return x * flag;
}
void write(int x) {
    if (x < 0) putchar('-'), x = -x;
    if (x >= 10) write(x / 10);
    putchar(x % 10 + 48);
}

const int Maxn = 3e5 + 9;
static int dp[Maxn][2], n;
static int x[Maxn], y[Maxn], k;

void init() {
    n = read(), k = read();
    rep (i, 1, n) x[i] = read();
    rep (i, 1, n) y[i] = read();
}

int getCalc(int preVal, int preSeparator, int nowVal, int nowSeparator) {
    int res = 0x3f3f3f3f;
    if (preVal < 0x3f3f3f3f) {
            LL lowerBound = ceil((1ll * preVal + nowVal) * 1. / k) - 1;
            if (nowSeparator < lowerBound) res = min(res, 0x3f3f3f3f);
            else if (nowSeparator > 1ll * nowVal * k) res = min(res, 0x3f3f3f3f);
            else if (nowSeparator > lowerBound) res = min(res, 1);
            else res = min(1ll * res, (1ll * preVal + nowVal) % k ? (1ll * preVal + nowVal) % k : k);
    }

	if (preSeparator < 0x3f3f3f3f) {
		LL lowerBound = ceil(nowVal * 1. / k) - 1;
            if (nowSeparator < lowerBound) res = min(res, 0x3f3f3f3f);
            else if (nowSeparator > 1ll * (nowVal - 1) * k + (k - preSeparator)) res = min(res, 0x3f3f3f3f);
            else if (nowSeparator > lowerBound) res = min(res, 1);
            else res = min(1ll * res, (1ll * nowVal) % k ? (1ll * nowVal) % k : k);
	}
    return res;
}

void solve() {
    dp[0][0] = 0; dp[0][1] = 0;

    rep (i, 1, n) {
        dp[i][0] = getCalc(dp[i - 1][0], dp[i - 1][1], x[i], y[i]);
        dp[i][1] = getCalc(dp[i - 1][1], dp[i - 1][0], y[i], x[i]);
    }

    puts(dp[n][0] <= k || dp[n][1] <= k ? "YES" : "NO");
}

int main() {

    init();
    solve();

#ifdef Qrsikno
    debug("
Running time: %.3lf(s)
", clock() * 1.0 / CLOCKS_PER_SEC);
#endif
    return 0;
}
原文地址:https://www.cnblogs.com/qrsikno/p/10003676.html