PAT 甲級 1044 Shopping in Mars (25 分)(滑動窗口,尺取法,也可二分)

1044 Shopping in Mars (25 分)
 

Shopping in Mars is quite a different experience. The Mars people pay by chained diamonds. Each diamond has a value (in Mars dollars M$). When making the payment, the chain can be cut at any position for only once and some of the diamonds are taken off the chain one by one. Once a diamond is off the chain, it cannot be taken back. For example, if we have a chain of 8 diamonds with values M$3, 2, 1, 5, 4, 6, 8, 7, and we must pay M$15. We may have 3 options:html

  1. Cut the chain between 4 and 6, and take off the diamonds from the position 1 to 5 (with values 3+2+1+5+4=15).
  2. Cut before 5 or after 6, and take off the diamonds from the position 4 to 6 (with values 5+4+6=15).
  3. Cut before 8, and take off the diamonds from the position 7 to 8 (with values 8+7=15).

Now given the chain of diamond values and the amount that a customer has to pay, you are supposed to list all the paying options for the customer.ios

If it is impossible to pay the exact amount, you must suggest solutions with minimum lost.數組

Input Specification:

Each input file contains one test case. For each case, the first line contains 2 numbers: N (≤), the total number of diamonds on the chain, and M (≤), the amount that the customer has to pay. Then the next line contains N positive numbers D1​​DN​​ (Di​​103​​ for all ,) which are the values of the diamonds. All the numbers in a line are separated by a space.ide

Output Specification:

For each test case, print i-j in a line for each pair of i ≤ j such that Di + ... + Dj = M. Note that if there are more than one solution, all the solutions must be printed in increasing order of i.測試

If there is no solution, output i-j for pairs of i ≤ j such that Di + ... + Dj > with (Di + ... + Dj −) minimized. Again all the solutions must be printed in increasing order of i.flex

It is guaranteed that the total value of diamonds is sufficient to pay the given amount.優化

Sample Input 1:

16 15
3 2 1 5 4 6 8 7 16 10 15 11 9 12 14 13

Sample Output 1:

1-5
4-6
7-8
11-11

Sample Input 2:

5 13
2 4 5 7 9

Sample Output 2:

2-4
4-5

 

題意:ui

 找到和不小於一個給定值、但儘量小的全部子串spa

 

題解:指針

 兩個指針,分別指向子串頭尾,具體看代碼(有優化,好比說找到一個知足要求的子串後,下一次掃描左指針右移一位,右指針的起始位置就保持在上一次右指針的位置便可)。

1.使用尺取法,若是取得範圍總和大於須要pay的,刪掉頭部

2.若是取得範圍綜合小於pay的,增長尾部

3.注意邊界狀況和沒有相等的狀況,細節可查看代碼

4.利用一個minAns的變量進行記錄答案數值

 

AC代碼:

#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<string>
#include<cstring>
using namespace std;
int a[100005];
int ans[100005];//數組開小了就測試點3一直不過
int k=0;
int n,m;
int cha=0x7fffffff;
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>a[i];
    }
    int r=1,l=1;
    int s=0;
    while(r<=n){
        while(s<m&&l<=n){
            s+=a[l];
            l++;
        }
        if(s<m){
            break;
        }
        else if(s<cha){
            k=0;
            ans[++k]=r;
            ans[++k]=l-1;
            cha=s;
        }else if(s==cha){
            ans[++k]=r;
            ans[++k]=l-1;
        }
        s-=a[r];
        r++;
    }
    for(int i=1;i<=k;i+=2){
        cout<<ans[i]<<"-"<<ans[i+1]<<endl;
    }
    return 0;
} 

 

也能夠用二分:

由於全部鑽石價值爲正,所以從開始到某位置的鏈條價值和恆正,在讀入價值時進行累加;

從第一個位置出發用二分法找到剛好大於或等於目標值的位置,並計算差值進行比較;

若有差值更小的數據組,則更新記錄;如找到差值剛好的數據組,加入記錄;

按照題目要求輸出結果,並返回零值。

#include<cstdio>
#include<fstream>
const int N=100010;
int sum[N];
int n, S, nears=100000010;
 
int upper_bound(int L, int R, int x){
    int left=L, right=R, mid;
    while(left<right){
        mid=(left+right)/2;
        if(sum[mid]>x){
            right=mid;
        } else{
            left=mid+1;
        }
    }
    return left;
}
 
int main(){
//    freopen("d://in.txt","r",stdin);
    scanf("%d%d", &n, &S);
    sum[0]=0;
    for(int i=1; i<=n; i++){
        scanf("%d", &sum[i]);
        sum[i]+=sum[i-1];
    }
    
    for(int i=1; i<=n; i++){
        int j=upper_bound(i, n+1, sum[i-1]+S);
        if(sum[j-1]-sum[i-1]==S){
            nears=S;
            break;
        } else if(j<=n && sum[j]-sum[i-1]<nears){
            nears=sum[j]-sum[i-1];
        }
    }
    
    for(int i=1; i<=n; i++){
        int j=upper_bound(i, n+1, sum[i-1]+nears);
        if(sum[j-1]-sum[i-1]==nears){
            printf("%d-%d\n", i, j-1);
        }
    }
    return 0;
}
View Code
相關文章
相關標籤/搜索