zoukankan      html  css  js  c++  java
  • poj 2566 Bound Found 尺取法 变形

    Bound Found
    Time Limit: 5000MS   Memory Limit: 65536K
    Total Submissions: 2277   Accepted: 703   Special Judge

    Description

    Signals of most probably extra-terrestrial origin have been received and digitalized by The Aeronautic and Space Administration (that must be going through a defiant phase: "But I want to use feet, not meters!"). Each signal seems to come in two parts: a sequence of n integer values and a non-negative integer t. We'll not go into details, but researchers found out that a signal encodes two integer values. These can be found as the lower and upper bound of a subrange of the sequence whose absolute value of its sum is closest to t. 

    You are given the sequence of n integers and the non-negative target t. You are to find a non-empty range of the sequence (i.e. a continuous subsequence) and output its lower index l and its upper index u. The absolute value of the sum of the values of the sequence from the l-th to the u-th element (inclusive) must be at least as close to t as the absolute value of the sum of any other non-empty range.

    Input

    The input file contains several test cases. Each test case starts with two numbers n and k. Input is terminated by n=k=0. Otherwise, 1<=n<=100000 and there follow n integers with absolute values <=10000 which constitute the sequence. Then follow k queries for this sequence. Each query is a target t with 0<=t<=1000000000.

    Output

    For each query output 3 numbers on a line: some closest absolute sum and the lower and upper indices of some range where this absolute sum is achieved. Possible indices start with 1 and go up to n.

    Sample Input

    5 1
    -10 -5 0 5 10
    3
    10 2
    -9 8 -7 6 -5 4 -3 2 -1 0
    5 11
    15 2
    -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1
    15 100
    0 0
    

    Sample Output

    5 4 4
    5 2 8
    9 1 1
    15 1 15
    15 1 15
    

    Source

    题意:给你n个数字,这些数字可正可负,再给你个数字t,求在这个数列中一个连续的子序列,和的绝对值与t相差最小
     
    错因分析:刚开始看到这道题目觉得很变态,尺取法怎么可能做得出来,这些数字是可正可负的,,后来看了题解,才恍然大悟,正因为是可正可负所以不能直接用尺取法去解题(尺取法必须是找到单调性),需要进行转化,找到单调性,但是a[i]数组是不能改变的,因为要求连续,那么就自然想到对a[i]求前缀和
     
    先贴上别人好的代码,核心思想:对sum进行从小到大的排序,注意需要加入<0,0>这点(为了求得单独的sum,就是从第一个节点到sum[i]对应的i节点),然后尺取法设置左右两个端点,直接在sum数组上进行尺取法,需要注意的是对两个端点移动的判断,假设得出的int temp=p[r].first - p[l].first<k,说明temp偏小,那么r端点右移,否则>k的话,说明temp偏大,需要l端点右移,但是需要注意不能出现l==r的情况,因为序列不能为空,l==r,则序列为空;还有一点很重要的是因为求得是和的绝对值,即|sum[j]-sum[i]|,那么只需要对sum数组进行从小到大排序,用大的减去小的就可以了(这也是去绝对值的体现)
    #include<cstdio>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <vector>
    #include <queue>
    #include<map>
    #include <algorithm>
    #include <set>
    using namespace std;
    #define MM(a) memset(a,0,sizeof(a))
    typedef long long LL;
    typedef unsigned long long ULL;
    const int mod = 1000000007;
    const double eps = 1e-10;
    const int inf = 0x3f3f3f3f;
    pair<int, int > p[100005];
    int n, m, k;
    void solve(int k)
    {
    	int l = 0, r = 1, al, ar, av, minn = inf;
    	  while (l<=n&&r<=n&&minn!=0)
    		{
    			int temp=p[r].first - p[l].first;
    			if (abs(temp - k) < minn)
    			{
    				minn = abs(temp - k);
    				ar = p[r].second;
    				al = p[l].second;
    				av = temp;
    			}
    			if (temp> k)
    				l++;
    			else if (temp < k)
    				r++;
    			else
    				break;
    			if (r == l)
    				r++;
    	   }
        if(al>ar)
            swap(al,ar);//因为al和ar大小没有必然关系()取绝对值,所以//要交换
    	printf("%d %d %d
    ", av, al+1, ar);
    }
    int main()
    {
    	while (~scanf("%d %d", &n, &m))
    	{
    		if (!n&&!m) return 0;
    		p[0] = make_pair(0, 0);
    		for (int i = 1; i <= n; i++)
    		{
    			scanf("%d", &p[i].first);
    			p[i].first += p[i - 1].first;
    			p[i].second = i;
    		}
    		sort(p, p + n + 1);
    		while (m--)
    		{
    			scanf("%d", &k);
    			solve(k);
    		}
    	}
    	return 0;
    }
    

      下面是自己的wa代码

         好好找茬

    #include<cstdio>
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <cstdlib>
    #include <cmath>
    #include <vector>
    #include <queue>
    #include<map>
    #include <algorithm>
    #include <set>
    using namespace std;
    #define MM(a) memset(a,0,sizeof(a))
    typedef long long LL;
    typedef unsigned long long ULL;
    const int mod = 1000000007;
    const double eps = 1e-10;
    const int inf = 0x3f3f3f3f;
    pair<int, int > p[100005];
    int n, m, k;
    void solve(int k)
    {
    	int l = 0, r = 1, al, ar, av, minn = inf;
    	  while (l<=n&&r<=n)
    		{
    			int temp = p[r].first - p[l].first;
    			if (abs(temp - k) < minn)
    			{
    				minn = abs(temp - k);
    				ar = p[r].second;
    				al = p[l].second;
    				av = temp;
    			}
    			if (temp > k)
    				l++;
    			else if (temp < k)
    				r++;
    			else
    				break;
    			if (r == l)
    				r++;
    	}
    	printf("%d %d %d
    ", av, al+1, ar);
    }
    int main()
    {
    	while (~scanf("%d %d", &n, &m))
    	{
    		if (!n&&!m) return 0;
    		p[0] = make_pair(0, 0);
    		for (int i = 1; i <= n; i++)
    		{
    			scanf("%d", &p[i].first);
    			p[i].first += p[i - 1].first;
    			p[i].second = i;
    		}
    		sort(p + 1, p + n + 1);
    		while (m--)
    		{
    			scanf("%d", &k);
    			solve(k);
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    JS DOM编程艺术——DOM获取元素—— JS学习笔记2015-7-6(第77天)
    JS DOM编程艺术的学习—— JS学习笔记2015-7-5(第76天)
    面向对象的程序设计1 理解对象—— JS学习笔记2015-7-4(第75天)
    JS 引用类型 Math 对象 JS学习笔记2015-7-3(第74天)
    JS 引用类型和值类型
    HTML5之应用缓存---manifest---缓存使用----Web前端manifest缓存
    易懂 易上手的cookie 最简单明了 js中cookie的使用方法及教程
    iOS开发-面试总结(十一)
    iOS开发-面试总结(十)
    iOS开发-面试总结(九)
  • 原文地址:https://www.cnblogs.com/smilesundream/p/5129758.html
Copyright © 2011-2022 走看看