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

    尺取法:顾名思义就是像尺子一样一段一段去取,保存每次的选取区间的左右端点。然后一直推进

    解决问题的思路:

    1. 先移动右端点 ,右端点推进的时候一般是加
    2. 然后推进左端点,左端点一般是减

    poj 2566 

    题意:从数列中找出连续序列,使得和的绝对值与目标数之差最小

    思路:

    1. 在原来的数列开头添加一个0
    2. 每次找到的区间为 [min(i,j)+1,max(i,j)]

    应用尺取法的代码:

     while (r <=n)
                           {
                                  int sub = pre[r].sum - pre[l].sum;
                                  while (abs(sub - t) < Min)
                                  {
                                          Min = abs(sub - t);
                                          ansl= min(pre[l].id, pre[r].id) + 1;
                                          ansr = max(pre[l].id, pre[r].id);
                                          ans = sub;
                                  }
                                  if (sub < t)
                                          r++;
                                  else if (sub > t) l++;
                                  else break;
                                  if (l == r) r++;
                           }

    解决问题的代码:

    #include <iostream>
    #include <stdio.h>
    #include <algorithm>
    #include <math.h>
    #include <cstring>
    #include <vector>
    #include <queue>
    using namespace std;
    const int N = 1e5 + 10;
    const int INF = 0x7fffffff;
    int n, k;
    int a[N];
    struct node {
            int sum, id;
    }pre[N];
    bool cmp(node a, node b)
    {
            return a.sum < b.sum;
    }
    int main()
    {
            while (scanf("%d%d", &n, &k) != EOF)
            {
                   if (n == 0 && k == 0) break;
                   pre[0].id = 0, pre[0].sum = 0;
                   for (int i = 1; i <= n; i++)
                   {
                           scanf("%d", &a[i]);
                           pre[i].id = i;
                           pre[i].sum = pre[i - 1].sum + a[i];
                   }
                   sort(pre, pre + n + 1, cmp);
                   for (int i = 0; i < k; i++)
                   {
                           int t;
                           scanf("%d", &t);
                           int Min = INF;
                           int l = 0, r = 1;
                           int ans, ansl, ansr;
                           while (r <=n)
                           {
                                  int sub = pre[r].sum - pre[l].sum;
                                  while (abs(sub - t) < Min)
                                  {
                                          Min = abs(sub - t);
                                          ansl= min(pre[l].id, pre[r].id) + 1;
                                          ansr = max(pre[l].id, pre[r].id);
                                          ans = sub;
                                  }
                                  if (sub < t)
                                          r++;
                                  else if (sub > t) l++;
                                  else break;
                                  if (l == r) r++;
                           }
                           printf("%d %d %d
    ", ans, ansl, ansr);
                   }
            }
            return 0;
    }

    poj 2739

    题意:将一个整数分解为连续的素数之和,有多少种分法?

    思路:

    1. 打表,先打出素数表
    2. 然后依次查询是否满足条件

    用尺取法的代码:

     for (;;) {
                           while (r < size&&sum < n)
                           {
                                  sum += primes[r++];
                           }
                           if (sum < n) break;
                           else if (sum == n) result++;
                           sum -= primes[l++];
                   }

    解决问题的代码:

    #include <iostream>
    #include <stdio.h>
    #include <algorithm>
    #include <math.h>
    #include <cstring>
    #include <vector>
    #include <queue>
    using namespace std;
    #define maxn 10000+16
    vector<int> primes;
    vector<bool> is_prime;
    void init_prime()
    {
            is_prime = vector<bool>(maxn + 1, true);
            is_prime[0] = is_prime[1] = false;
            for (int i = 2; i < maxn; i++)
            {
                   if (is_prime[i])
                   {
                           primes.push_back(i);
                           for (int j = i * 2; j < maxn; j += i)
                           {
                                  is_prime[j] = false;
                           }
                   }
            }
    }
    int main()
    {
            int n;
            init_prime();
            int size = primes.size();
            while (cin >> n && n)
            {
                   int result = 0, sum = 0;
                   int l = 0,r = 0;
                   for (;;) {
                           while (r < size&&sum < n)
                           {
                                  sum += primes[r++];
                           }
                           if (sum < n) break;
                           else if (sum == n) result++;
                           sum -= primes[l++];
                   }
                   printf("%d
    ", result);
            }
            return 0;
    }

    poj 2100

    题意:将一个整数分解为连续数平方之和,有多少种分法?

    解决问题的思路:

    1. 右端点移动,sum+=r*r;
    2. 如果满足答案就 push (l,r)
    3. 左端点移动 sum-=l*l;

    用尺取法的代码:

     for (;;)
            {
                   while (sum < n)
                   {
                           sq = r * r;
                           sum += sq;
                           r++;
                   }
                   if (sq > n) break;
                   else if (sum == n) ans.push_back(make_pair(l, r));
                   sum -= l * l;
                   l++;
            }

    解决问题的代码:

    #include <iostream>
    #include <stdio.h>
    #include <algorithm>
    #include <math.h>
    #include <cstring>
    #include <vector>
    #include <queue>
    using namespace std;
    
    typedef long long ll;
    vector<pair<ll, ll>> ans;
    void solve(ll n)
    {
        ll l = 1, r = 1, sum = 0, sq;
        for (;;)
        {
            while (sum < n)
            {
                sq = r * r;
                sum += sq;
                r++;
            }
            if (sq > n) break;
            else if (sum == n) ans.push_back(make_pair(l, r));
            sum -= l * l;
            l++;
        }
        ll size = ans.size();
        printf("%lld
    ", size);
        for (ll i = 0; i < size; i++)
        {
            ll ansr = ans[i].second;
            ll ansl = ans[i].first;
            printf("%lld",ansr-ansl);
            for (ll j=ansl;j<ansr;j++)
                printf(" %lld", j);
            printf("
    ");
        }
    }
    
    int main()
    {
        ll n;
        while (scanf("%lld", &n) != EOF)
        {
            if (n == 0) break;
            solve(n);
        }
        return 0;
    }
    君子知命不惧,自当日日自新
  • 相关阅读:
    给Lisp程序员的Python简介
    QuickLisp常用命令
    修改windows cmd字体
    Eclipse生成JavaDoc时指定字符集, 避免页面乱码
    css颜色名
    css3动画
    使用placeholder实现动态配置persistence.xml
    spring下配置tomcat jdbc pool 报找不到"com.mysql.jdbc.Driver"类
    去除移动端浏览器点击元素时的边框
    JS经典闭包问题
  • 原文地址:https://www.cnblogs.com/xuxiaojin/p/9429853.html
Copyright © 2011-2022 走看看