• [POJ3061]Subsequence(二分,前缀和)


    题目链接:http://poj.org/problem?id=3061

    题意:给一个长为n的数列和整数s,求一个连续的子序列,使得这个子序列长度最短并且不小于这个整数s。

    统计[1~i]的子序列和sum(i),(sum(0)=0)。然后求一个区间[i,j]的和即为sum(j)-sum(i-1) (i > 0)。

    由于给定序列没有负数,因此sum是个严格不减的序列。

    转换成一个求最大值最小的问题,可以二分枚举序列长度,在前缀和上计算子序列[i-1,i+m-1]的和。如果存在一个满足子序列和≥s的,则缩小序列长度并记下当前值,反之扩大。复杂度为O(nlgn)。

     1 #include <algorithm>
     2 #include <iostream>
     3 #include <iomanip>
     4 #include <cstring>
     5 #include <climits>
     6 #include <complex>
     7 #include <fstream>
     8 #include <cassert>
     9 #include <cstdio>
    10 #include <bitset>
    11 #include <vector>
    12 #include <deque>
    13 #include <queue>
    14 #include <stack>
    15 #include <ctime>
    16 #include <set>
    17 #include <map>
    18 #include <cmath>
    19 
    20 using namespace std;
    21 
    22 const int maxn = 100010;
    23 int n, s;
    24 int x[maxn];
    25 int sum[maxn];
    26 
    27 bool ok(int mm) {
    28     for(int i = 1; i <= n - mm + 1; i++) {
    29         // printf("%d %d
    ", i-1, i+mm-1);
    30         if(sum[i+mm-1] - sum[i-1] >= s) return 1;
    31     }
    32     return 0;
    33 }
    34 
    35 int main() {
    36     // freopen("in", "r", stdin);
    37     int T;
    38     scanf("%d", &T);
    39     while(T--) {
    40         memset(sum, 0, sizeof(sum));
    41         scanf("%d %d", &n, &s);
    42         for(int i = 1; i <= n; i++) {
    43             scanf("%d", &x[i]);
    44             sum[i] = sum[i-1] + x[i];
    45         }
    46         if(sum[n] < s) {
    47             printf("0
    ");
    48             continue;
    49         }
    50         int ans;
    51         int ll = 0;
    52         int rr = n;
    53         while(ll <= rr) {
    54             int mm = (ll + rr) >> 1;
    55             if(ok(mm)) {
    56                 ans = mm;
    57                 rr = mm - 1;
    58             }
    59             else ll = mm + 1;
    60         }
    61         printf("%d
    ", ans);
    62     }
    63 }

    此题也可以用尺取法,维护两个指针从左到右扫描所存序列,复杂度为O(n)。

     1 #include <algorithm>
     2 #include <iostream>
     3 #include <iomanip>
     4 #include <cstring>
     5 #include <climits>
     6 #include <complex>
     7 #include <fstream>
     8 #include <cassert>
     9 #include <cstdio>
    10 #include <bitset>
    11 #include <vector>
    12 #include <deque>
    13 #include <queue>
    14 #include <stack>
    15 #include <ctime>
    16 #include <set>
    17 #include <map>
    18 #include <cmath>
    19 
    20 using namespace std;
    21 
    22 const int maxn = 100010;
    23 int n, s;
    24 int x[maxn];
    25 
    26 int main() {
    27     // freopen("in", "r", stdin);
    28     int T;
    29     scanf("%d", &T);
    30     while(T--) {
    31         scanf("%d %d", &n, &s);
    32         int sum = 0;
    33         for(int i = 1; i <= n; i++) {
    34             scanf("%d", &x[i]);
    35             sum += x[i];
    36         }
    37         if(sum < s) {
    38             printf("0
    ");
    39             continue;
    40         }
    41         int ans = 0x7f7f7f;
    42         int ll = 1;
    43         int rr = 1;
    44         sum = 0;
    45         while(1) {
    46             while(rr <= n && sum <= s) {
    47                 sum += x[rr++];
    48             }
    49             if(sum < s) break;
    50             ans = min(ans, rr-ll);
    51             sum -= x[ll++];
    52         }
    53         printf("%d
    ", ans);
    54     }
    55 }
  • 相关阅读:
    Navicat 连接MySQL 8.0.11 出现2059错误
    安全技术运营的心得
    浅谈命令混淆
    2021年度总结与2022新的展望
    域环境搭建之安装exchange
    内网ADCS攻防
    CVE202142287复现
    企业安全建设——安全防线框架建设(一)
    frp_v0.37.1内网穿透,内网服务公网用不求人
    WP7XNA 多点触摸
  • 原文地址:https://www.cnblogs.com/kirai/p/5405006.html
Copyright © 2020-2023  润新知