zoukankan      html  css  js  c++  java
  • 尺取法

    今天学了个高级东西——尺取法。(这句话在很多大佬看来是个笑话)。

    以下摘自《挑战程序设计竞赛(第二版)》

    尺取法通常指对数组保存一对下标(起点和终点),然后根据实际情况交替推进两个端点直到得到答案的方法。这种操作很像是尺蠖(日文中称为尺取虫)爬行的方式故得名。

    举几个栗子:
    POJ-3061
    题意是给你一个正整数数列,一个整数 (S),问和不小于 (S) 的连续子序列的最小长度,无解输出 (0)
    尺取法入门题。
    题目保证 (a_i > 0),所以右端点具有单调性,故可以用尺取法。
    按照尺取法,设定前后指针 (s=0)(t=0),然后将 (t) 向前移动,判断 (s) ~ (t) 之间的区间是否满足要求,如果小于 (S)(t) 继续移动,直到和大于等于 (S) 为止。此时将 (t) 向前移动。反复进行该过程,期间记录长度,并更新长度的最小值。复杂度为 (O(n))

    #include <bits/stdc++.h>
    using namespace std;
    
    #define db double
    #define ll long long
    #define RG register
    
    inline int gi()
    {
    	RG int ret; RG bool flag; RG char ch;
    	ret=0, flag=true, ch=getchar();
    	while (ch < '0' || ch > '9')
    		ch == '-' ? flag=false : 0, ch=getchar();
    	while (ch >= '0' && ch <= '9')
    		ret=(ret<<3)+(ret<<1)+ch-'0', ch=getchar();
    	return flag ? ret : -ret;
    }
    
    const db pi = acos(-1.0);
    const int N = 1e5+5, inf = 1<<30;
    
    int a[N];
    
    inline void work()
    {
    	int l,r,i,n,lim,s,ans;
    	n=gi(), lim=gi();
    	for (i=1; i<=n; ++i)
    		a[i]=gi();
    	l=r=1, s=a[l], ans=inf;
    	while (r <= n)
    		{
    			while (s < lim && r <= n)
    				s+=a[++r];
    			if (s < lim)
    				break;
    			ans=min(ans,r-l+1), s-=a[l++];
    		}
    	ans < inf ? printf("%d
    ",ans) :puts("0");
    }
    
    int main()
    {
    	// freopen("sub.in","r",stdin);
    	// freopen("sub.out","w",stdout);
    	int t;
    	t=gi();
    	while (t--)
    		work();
    	return 0;
    }
    

    NOI2016 【区间】
    题目不解释了。
    首先,喻队长教育我:

    “他坐标范围这么大,肯定要离散化,所以交点一定可以在端点上。”

    傻逼的我想了30秒,发现好有道理:

    判断是否有交是左端点取 (max),右端点取 (min)

    于是只需要每次判断是否有一个区间的一个端点被覆盖 (m) 次即可。
    剩下的部分就是贪心了。
    把区间按长度排序即可。然后用尺取法,每次用线段树维护一下所有点被覆盖次数的 (max) 即可。
    至于为什么可以一直加,是因为这个区间就算不在 (h) 的要选的 (m) 个区间内,它选了也不会对答案造成影响,因为后面肯定还有必须要选的区间 (t),即当前点要选的第 (m) 个区间。(这个有点像最大子序列和的思想)

    #include <bits/stdc++.h>
    using namespace std;
    
    #define db double
    #define ll long long
    #define RG register
    
    inline int gi()
    {
    	RG int ret; RG bool flag; RG char ch;
    	ret=0, flag=true, ch=getchar();
    	while (ch < '0' || ch > '9')
    		ch == '-' ? flag=false : 0, ch=getchar();
    	while (ch >= '0' && ch <= '9')
    		ret=(ret<<3)+(ret<<1)+ch-'0', ch=getchar();
    	return flag ? ret : -ret;
    }
    
    const db pi = acos(-1.0);
    const int N = 1e6+5, inf = (1ll<<31)-10;
    
    struct ran
    {
    	int l,r,len;
    	inline bool operator <(const ran &R) const { return len < R.len; }
    }r[N];
    int b[N<<1],tr[N<<2],lz[N<<2];
    
    inline void down(RG int o)
    {
    	if (!lz[o])
    		return;
    	RG int ls,rs;
    	ls=o<<1, rs=ls|1;
    	lz[ls]+=lz[o], lz[rs]+=lz[o];
    	tr[ls]+=lz[o], tr[rs]+=lz[o];
    	lz[o]=0;
    }
    
    inline void update(RG int o,RG int l,RG int r,RG int s,RG int t,RG int w)
    {
    	if (l >= s && r <= t)
    		{
    			tr[o]+=w, lz[o]+=w;
    			return;
    		}
    	down(o);
    	RG int mid,ls,rs;
    	mid=(l+r)>>1, ls=o<<1, rs=ls|1;
    	if (s <= mid)
    		update(ls,l,mid,s,t,w);
    	if (t > mid)
    		update(rs,mid+1,r,s,t,w);
    	tr[o]=max(tr[ls],tr[rs]);
    }
    
    int main()
    {
    	// freopen("ran.in","r",stdin);
    	// freopen("ran.out","w",stdout);
    	int n,m;
    	RG int h,t,cnt,i,ans;
    	n=gi(), m=gi();
    	cnt=0;
    	for (i=1; i<=n; ++i)
    		{
    			r[i].l=gi(), r[i].r=gi(), r[i].len=r[i].r-r[i].l;
    			b[++cnt]=r[i].l, b[++cnt]=r[i].r;
    		}
    	sort(r+1,r+n+1);
    	sort(b+1,b+cnt+1);
    	cnt=unique(b+1,b+cnt+1)-b-1;
    	for (i=1; i<=n; ++i)
    		{
    			r[i].l=lower_bound(b+1,b+cnt+1,r[i].l)-b;
    			r[i].r=lower_bound(b+1,b+cnt+1,r[i].r)-b;
    		}
    	h=t=1, ans=inf;
    	while (true)
    		{
    			while (tr[1] < m && t <= n)
    				update(1,1,cnt,r[t].l,r[t].r,1), t++;
    			if (tr[1] < m)
    				break;
    			ans=min(ans,r[t-1].len-r[h].len);
    			update(1,1,cnt,r[h].l,r[h].r,-1), h++;
    		}
    	ans < inf ? printf("%d
    ",ans) : puts("-1");
    	return 0;
    }
    
  • 相关阅读:
    从尾到头打印链表-Python
    上台阶三种实现(斐波那契数列)-Python
    Windows/Linux安装python2.7,pycharm和pandas——《利用Python进行数据分析》
    部署(Django )
    第一个Django模型
    第一个Django Project(创建一个简单的博客)
    几个算法基础
    回文序列—Palindrome
    学习笔记:CentOS7学习之二十:shell脚本的基础
    学习笔记:CentOS7学习之十七: Linux计划任务与日志的管理
  • 原文地址:https://www.cnblogs.com/y142857/p/7588396.html
Copyright © 2011-2022 走看看