Codeforces Round #587 (Div. 3) F :WiFi ( dp + 贪心 )

添加链接描述
题目大意就是给你一串n为长度由01组成的串,再给你一个k代表路由器的信号范围,串中1代表可以在这里放路由器,0代表不行,使一个点有信号有两种办法

  1. 点i直接连宽带,花费i的钱(i从1~n)
  2. 在max(1, i-k) or min(n, i+k)的地方(也就是信号范围内)已经设置了路由器,路由器的信号可以覆盖到这一点,那么这一点就不用花任何钱就有信号。
    当然路由器也是要花钱的,花费和连宽带相同,也就是在点i放置路由器, 花费i的钱
    现在要你求出让i个点都有信号所花的最少的钱

思路大体是dp, dp[i]表示到第i点所花的最少钱,我是从后往前看(当然也可以从前往后看), 每一点都有两种可能的方法:
3. 最无脑 ,直接连宽带 ,花费i的钱。 dp[i-1] = min(dp[i-1], dp[i] + i)从(0~n-1编号)
4. 若有一个路由器再与他 k 的信号范围内,就设他的坐标为x吧,那么一直到max(0, x-k)的范围内都有信号,那么在max(0, x-k)这个点的最优解就求出来了。贪心的思想就是如果有不止一个路由器可以放在k的范围内,那你肯定选与当前最远(最靠近0)的那个位置放,为什么?因为首先越靠近0他放置一个路由器所花的钱越少, 其次他还能覆盖到更多的范围,所以去最左边切不超过k的那个’1’点放置路由器最优的,这里可以预处理一个pre[]数组来表示这个,用 i - pre[i] <= k来判断能不能通过放路由器的方式来使这点有信号。
int idx = max(0, pre[i-1] - k);
dp[idx] = min(dp[idx], dp[i] + pre[i-1] + 1);

下面是ac代码

#include <bits/stdc++.h>

typedef long long ll;

using namespace std;

const ll maxn = 2 * (int)1e5 + 100;
const ll INF = (ll)1e18;
ll n, k, dp[maxn], pre[maxn]; 
string s;

inline ll mymax(ll a, ll b) {
	if (a > b) return a;
	else return b;
}
inline ll mymin(ll a, ll b) {
	if (a < b) return a;
	else return b;
}


int main() {
	ios::sync_with_stdio(false); cin.tie(0);
	cin >> n >> k;
	cin >> s;
	if (k >= n) {
		cout << 1 << '\n';
		return 0;
	}
	ll cur = -4 * n;
	for (int i = 0; i < n; ++i) {
		pre[i] = cur;
	}
	for (int i = n-1; i >= -k; --i) {
		if (i >= 0  && s[i] == '1') {
			cur = i;
		}
		if (i + k < n) {
			pre[i + k] = cur;
		}
	}
	for (int i = 0; i < n; ++i) {
		dp[i] = INF;
	}
	dp[n] = 0;
	for (int i = n; i > 0; --i) {
		if ((i-1) - pre[i-1] <= k) {
			int idx = mymax(0, pre[i-1] - k);
			dp[idx] = mymin(dp[idx], pre[i-1] + 1 + dp[i]);
		}
		dp[i-1] = mymin(dp[i-1], dp[i] + i);
	}
	cout << dp[0] << '\n';
	return 0;
} 
发布了51 篇原创文章 · 获赞 6 · 访问量 1665

猜你喜欢

转载自blog.csdn.net/qq_43555854/article/details/101442892