VP Educational Codeforces Round 53 (Rated for Div. 2)


A. Diverse Substring

看能不能选两个不一样的字符。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::string s;
    std::cin >> s;
    if (std::ranges::count(s, s[0]) == n) {
    	std::cout << "NO\n";
    	return;
    }

    std::cout << "YES\n";
    std::string ans;
    ans += s[0];
    for (auto & c : s) {
    	if (c != s[0]) {
    		ans += c;
    		break;
    	}
    }

    std::cout << ans << "\n";
}

B. Vasya and Books

按题意模拟。用一个指针记录用到了\(b\)数组哪个位置。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::set<int> s;
    std::vector<int> a(n), b(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    	s.insert(a[i]);
    }

    for (int i = 0; i < n; ++ i) {
    	std::cin >> b[i];
    }

    for (int i = 0, j = 0; i < n; ++ i) {
    	if (!s.count(b[i])) {
    		std::cout << 0 << " \n"[i == n - 1];
    	} else {
    		int ans = 0;
    		while (a[j] != b[i]) {
    			s.erase(a[j]);
    			++ j;
    			++ ans;
    		}

    		s.erase(b[i]);
    		++ j;

    		std::cout << ans + 1 << " \n"[i == n - 1];
    	}
    }
}

C. Vasya and Robot

题意:给你一个上下左右的移动序列,你需要选一个子区间任意更改,使得最后位置在\((x, y)\)。求最短的子区间。

任意更改,可以改也可以不改,那么如果短区间可以操作,那么长区间也可以。考虑二分。
通过前缀和维护,然后二分区间长度,对于每个区间可以求出除了它后剩下可以操作到哪里,然后得到横纵坐标差了多少,这个差的值不能超过区间长度,同时操作完后剩下的操作数不能是奇数。

点击查看代码
void solve() {
    int n;
    std::cin >> n;
    std::string s;
    std::cin >> s;
    int tx, ty;
    std::cin >> tx >> ty;
    std::vector<int> prex(n + 1), prey(n + 1);
    for (int i = 0; i < n; ++ i) {
    	prex[i + 1] = prex[i];
    	prey[i + 1] = prey[i];
    	if (s[i] == 'U') {
    		prey[i + 1] += 1;
    	} else if (s[i] == 'D') {
    		prey[i + 1] -= 1;
    	} else if (s[i] == 'L') {
    		prex[i + 1] -= 1;
    	} else {
    		prex[i + 1] += 1;
    	}
    }

    if (prex[n] == tx && prey[n] == ty) {
    	std::cout << 0 << "\n";
    	return;
    }

    auto check = [&](int len) -> bool {
    	for (int i = 1; i + len - 1 <= n; ++ i) {
    		int j = i + len - 1;
    		int dx = prex[i - 1] + prex[n] - prex[j];
    		int dy = prey[i - 1] + prey[n] - prey[j];
    		int d = std::abs(dx - tx) + std::abs(dy - ty);
    		if (d <= len && (len - d) % 2 == 0) {
    			return true;
    		}
    	}

    	return false;
    };

    int l = 1, r = n;
    while (l < r) {
    	int mid = l + r >> 1;
    	if (check(mid)) {
    		r = mid;
    	} else {
    		l = mid + 1;
    	}
    }

    if (!check(l)) {
    	std::cout << -1 << "\n";
    	return;
    }
    std::cout << l << "\n";
}

D. Berland Fair

题意:一个人在一个环上依次买东西,直到它买不到任何东西为止。求能买多少东西。

模拟。每次模拟一遍把能拿的拿了,然后直接求出能拿几轮。然后减去。
模拟次数很少。

点击查看代码
void solve() {
    int n;
    i64 m;
    std::cin >> n >> m;
    std::vector<int> a(n);
    for (int i = 0; i < n; ++ i) {
    	std::cin >> a[i];
    }

    i64 ans = 0;
    while (1) {
    	i64 sum = 0, cnt = 0;
    	for (int i = 0; i < n; ++ i) {
    		if (sum + a[i] <= m) {
    			sum += a[i];
    			++ cnt;
    		}
    	}

    	if (sum == 0) {
    		break;
    	}

    	ans += m / sum * cnt;
    	m -= m / sum * sum;
    }

    std::cout << ans << "\n";
}

E. Segment Sum

题意:求\([l, r]\)里不同数不超过\(k\)个的数的个数。

明显的数位\(dp\)
\(f[i][j][l][r]\)为到第\(i\)位,状态为\(j\),有没有前导零,有没有限制的答案。\(j\)是二进制数,每一位代表这个数有没有出现过。
但发现可能有很多数满足某个状态,导致无法计算所有状态。考虑把他们合并,用\(g[i][j][l][r]\)表示这个状态后续合法的数字个数,那么\(f[i][j][l][r] = \sum_{x=0}^{9} x \times 10^i \times g[i - 1][j'][l'][r'], g[i][j][l][r] = \sum_{x=0}^{9} g[i-1][j'][l'][r']\)

点击查看代码
const int mod = 998244353;

int f[20][1024][2][2];
int g[20][1024][2][2];

void solve() {
    i64 l, r;
    int k;
    std::cin >> l >> r >> k;

    std::vector<int> P(20);
    P[0] = 1;
    for (int i = 1; i < 20; ++ i) {
    	P[i] = P[i - 1] * 10ll % mod;
    }

    auto add = [&](int & x, const int & y) {
    	x += y;
    	if (x >= mod) {
    		x -= mod;
    	}
    };

    auto dp = [&](i64 n) -> int {
    	std::string s = std::to_string(n);
    	std::ranges::reverse(s);
	    memset(f, -1, sizeof f);
	    memset(g, -1, sizeof g);

    	auto dfs = [&](auto & self, int u, int state, int zero, int limit) -> std::pair<int, int> {
    		if (u < 0) {
    			return {0, __builtin_popcount(state) <= k};
    		}

    		if (f[u][state][zero][limit] != -1) {
    			return {f[u][state][zero][limit], g[u][state][zero][limit]};
    		}

    		f[u][state][zero][limit] = g[u][state][zero][limit] = 0;
    		int up = limit ? s[u] - '0' : 9;
    		for (int i = 0; i <= up; ++ i) {
    			int nstate = zero && i == 0 ? state : (state | (1 << i));
    			auto next = self(self, u - 1, nstate, zero && i == 0, limit && i == up);
    			add(f[u][state][zero][limit], next.first);
    			add(f[u][state][zero][limit], 1ll * P[u] * i % mod * next.second % mod);
    			add(g[u][state][zero][limit], next.second);
    		}

    		return {f[u][state][zero][limit], g[u][state][zero][limit]};
    	};

    	dfs(dfs, (int)s.size() - 1, 0, 1, 1);
    	return f[(int)s.size() - 1][0][1][1];
    };

    std::cout << (dp(r) - dp(l - 1) + mod) % mod << "\n";
}
posted @ 2025-04-07 17:25  maburb  阅读(14)  评论(0)    收藏  举报