zoukankan      html  css  js  c++  java
  • JZOJ 捕老鼠

    题目

    实际上经转换得:
    给了 (n(n le 5 imes 10^5)) 条线段,求覆盖 ([1..n]) 需要的最少条数

    分析

    (f_i) 表示覆盖了 ([1..n]) 时需要的最少的线段数
    那么 (O(n^2)) 的转移是这样的

    #include<cstdio>
    #include<iostream>
    using namespace std;
    
    const int N = 5e5 + 5;
    int n , a[N] , f[N];
    
    int main()
    {
    	scanf("%d" , &n);
    	for(register int i = 1; i <= n; i++) scanf("%d" , a + i) , f[i] = N;
    	for(register int i = 1; i <= n; i++)
    		for(register int j = 1; j <= n; j++)
    		{
    			int l = max(j - a[j] , 1) , r = min(j + a[j] , n);
    			if (l <= i && i <= r) f[i] = min(f[i] , f[l - 1] + 1);
    		}
    	printf("%d" , f[n]);
    }
    

    而我们发现在转移时,(f_i) 的要取所有满足条件的线段的 (f_{l-1}) 的最小值
    而要满足的条件就是 (l leq i leq r)
    于是我们用线段树维护
    逆着考虑,维护每个 (f_i) 能影响的范围

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #define ls (k << 1)
    #define rs (ls | 1)
    using namespace std;
    
    const int N = 5e5 + 5 , INF = 0x3f3f3f3f;
    int n , f[N] , nxt[N] , seg[N * 4] , tag[N * 4];
    struct node{
    	int l , r;
    }a[N];
    
    void pushdown(int k)
    {
    	if (tag[k] == INF) return;
    	seg[ls] = min(seg[ls] , tag[k]) , tag[ls] = min(tag[ls] , tag[k]);
    	seg[rs] = min(seg[rs] , tag[k]) , tag[rs] = min(tag[rs] , tag[k]);
    	tag[k] = INF;
    }
    
    void update(int l , int r , int k , int tl , int tr , int v)
    {
    	if (tl <= l && r <= tr)
    	{
    		seg[k] = min(seg[k] , v) , tag[k] = min(tag[k] , v);
    		return;
    	}
    	pushdown(k);
    	int mid = (l + r) >> 1;
    	if (tl <= mid) update(l , mid , ls , tl , tr , v);
    	if (tr > mid) update(mid + 1 , r , rs , tl , tr , v);
    	seg[k] = min(seg[ls] , seg[rs]);
    }
    
    int query(int l , int r , int k , int x)
    {
    	if (l == r && l == x) return seg[k];
    	pushdown(k);
    	int mid = (l + r) >> 1;
    	if (x <= mid) return query(l , mid , ls , x);
    	if (x > mid) return query(mid + 1 , r , rs , x);
    }
    
    int main()
    {
    	scanf("%d" , &n);
    	int x;
    	for(register int i = 1; i <= n; i++) 
    	{
    		scanf("%d" , &x);
    		a[i].l = max(i - x , 1) , a[i].r = min(i + x , n);
    		if (a[nxt[a[i].l - 1]].r < a[i].r) nxt[a[i].l - 1] = i;
    	}
    	memset(seg , 0x3f3f3f3f , sizeof seg) , memset(tag , 0x3f3f3f3f , sizeof tag);
    	if (nxt[0] != 0) update(1 , n , 1 , a[nxt[0]].l , a[nxt[0]].r , 0);
    	for(register int i = 1; i <= n; i++)
    	{
    		f[i] = query(1 , n , 1 , i) + 1;
    		if (nxt[i] != 0) update(1 , n , 1 , a[nxt[i]].l , a[nxt[i]].r , f[i]);
    	}
    	printf("%d" , f[n]);
    }
    
  • 相关阅读:
    数据压缩和归档
    数据持久化
    文件和目录的使用
    数据及数据处理
    data types
    string services
    logging模块
    指导
    比较两个NSDate类型的参数相差的时间差
    推送 iOS 10
  • 原文地址:https://www.cnblogs.com/leiyuanze/p/13905674.html
Copyright © 2011-2022 走看看