zoukankan      html  css  js  c++  java
  • CodeForces1216F-Wi-Fi (DP+线段树优化)

    题意:给定n和k,n表示n个房间,k表示wifi的传播范围,同时给定一个字符串,表示可以放置路由器的房间,如果可以放置路由器,那么max(1, n - k)
    和min(n, n + k)范围里的房间都可以得到信号,从而可以不直接联网,每个房间联网的代价为它的下标i。

    分析:
    我们假设f[i][0 / 1]表示第i号房间不联网/联网的最小代价。
    如果联网了,并且这个房间里面由wifi,那就更好,可以从更前面的状态转移过来,否则就从前面一个房间转移过来。

    如果f[i][0] (表示第i个房间不联网),显然它需要从前面有wifi的地方转移过来,
    如果f[i][1] (表示第i个房间联网),那么它有wifi的话,可以从更前面转移过来,如果没有wifi,那就从前面一个转移过来。

    但是这样做的时间复杂度为o(n * k)

    不优化的代码,TLE在23个点

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
     
    using namespace std;
    const int N = 200005;
     
    char s[N];
    int f[N][2];
     
    int main()
    {
    	int n, k;
    	scanf("%d%d", &n, &k);
    	scanf("%s", s + 1);
     
    	memset(f, 0x3f, sizeof f);
    	f[0][0] = 0, f[0][1] = 0;
    	for (int i = 1; i <= n; ++i)
    	{
    		if (s[i] == '0')
    		f[i][1] = min(f[i][1], min(f[i - 1][0], f[i - 1][1]) + i);
    		for (int j = 0; j <= i - 1; ++j)
    		{
    			if (s[j] == '1' && j + k >= i)
    				f[i][0] = min(f[i][0], f[j][1]);
    			if (s[i] == '1' && j >= i - k - 1)
    				f[i][1] = min(f[i][1], min(f[j][0], f[j][1]) + i);
    		}
    	}
     
    	printf("%d
    ", min(f[n][1], f[n][0]));
     
     
     
    	return 0;
    }
    

    通过线段树维护区间最小值的代码
    这里用了三棵线段树,因为我需要从前面有wifi并且状态是联网的房间转移过来,所以不得已再维护一个线段树。
    因为我的状态定义和其它博客的不一样,其它博客表示f[i][0/1]这个房间有没有路由,但是这样我觉的分不清楚。

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
     
    using namespace std;
    using LL = long long;
    const int N = 200005;
    const LL inf = 1e18;
    char s[N];
    LL f[N][2];
    //0:不买 1:买
     
    struct ST
    {
    	int l, r;
    	LL val;
    };
    //tr维护不买的,tr2维护买的
    ST tr[N * 4], tr2[N * 4], tr3[N * 4];//三棵线段树
     
    void pushup(ST tr[], int u)
    {
    	tr[u].val = min(tr[u].val, tr[u << 1].val);
    	tr[u].val = min(tr[u].val, tr[u << 1 | 1].val);
    }
     
    void build(ST tr[], int u, int l, int r)
    {
    	tr[u].l = l, tr[u].r = r, tr[u].val = inf;
    	if (l == r)
    	{
    		//tr[u].val = inf;
    		return;
    	}
    	int mid = tr[u].l + tr[u].r >> 1;
    	build(tr, u << 1, l, mid), build(tr, u << 1 | 1, mid + 1, r);
    	//pushup(tr, u);
    }
     
    //单点修改
    void modify(ST tr[], int u, int pos, LL v)
    {
    	if (tr[u].l == tr[u].r)
    	{
    		tr[u].val = v;
    		return;
    	}
    	int mid = tr[u].l + tr[u].r >> 1;
    	if (pos <= mid) modify(tr, u << 1, pos, v);
    	else if (pos > mid) modify(tr, u << 1 | 1, pos, v);
    	pushup(tr, u);
    }
     
    //区间查询最小值
     
    LL query(ST tr[], int u, int l, int r)
    {
    	if (l <= tr[u].l && r >= tr[u].r)
    	{
    		return tr[u].val;
    	}
    	int mid = tr[u].l + tr[u].r >> 1;
    	LL res = inf;
    	if (l <= mid) res = min(res, query(tr, u << 1, l, r));
    	if (r > mid) res = min(res, query(tr, u << 1 | 1, l, r));
    	return res;
    }
     
     
    int main()
    {
    	int n, k;
    	scanf("%d%d", &n, &k);
    	scanf("%s", s + 1);
     
    	build(tr, 1, 0, n);
    	build(tr2, 1, 0, n);
    	build(tr3, 1, 0, n);
     
    	for (int i = 1; i <= n; ++i)
    		f[i][0] = f[i][1] = inf;
    	modify(tr, 1, 0, 0);//f[i][0]
    	modify(tr2, 1, 0, 0);//f[i][1]
    	f[0][0] = 0, f[0][1] = 0;
    	for (int i = 1; i <= n; ++i)
    	{
    		//没有路由,并且购买了的
    		if (s[i] == '0')
    		{
    			LL q = min(f[i - 1][0], f[i - 1][1]);
    			if (f[i][1] > q + i)
    			{
    				f[i][1] = q + i;
    				modify(tr2, 1, i, f[i][1]);
    			}
    		}
    		//没有购买,由前面的wifi提供
    		LL res = query(tr3, 1, max(1, i - k), i - 1);
    		if (f[i][0] > res)
    		{
    			f[i][0] = res;
    			modify(tr, 1, i, f[i][0]);
    		}
    		res = inf;
    		res = min(res, query(tr, 1, max(0, i - k - 1), i - 1));
    		res = min(res, query(tr2, 1, max(0, i - k - 1), i - 1));
    		if (s[i] == '1')
    		{
    			f[i][1] = res + i;
    			modify(tr2, 1, i, f[i][1]);
    			modify(tr3, 1, i, f[i][1]);
    		}		
    	}
     
    	printf("%lld
    ", min(f[n][1], f[n][0]));
     
     
     
    	return 0;
    }
    
    
    
    
    
    
    
    
    
    
    
    
    
  • 相关阅读:
    上下文切换
    NUMA的取舍与优化设置
    KVM CPU线程等学习记录
    openstack cpu pinning
    virt-install详解
    对KVM虚拟机进行cpu pinning配置的方法
    30 个 OpenStack 经典面试问题和解答
    OpenFace Docker 使用简介
    单链表、双链表及单链表的逆序
    Ubuntu14.04.1安装搜狗拼音输入法
  • 原文地址:https://www.cnblogs.com/pixel-Teee/p/12810245.html
Copyright © 2011-2022 走看看