1. 程式人生 > >牛客練習賽34 D little w and Exchange(歸納)

牛客練習賽34 D little w and Exchange(歸納)

題意:

給n個數,和m

問這組數是否可以構成[1, m]中的每一個數

思路:

先將a陣列排序。

先算算構成前幾個數需要什麼,至少需要a[1]=1

需要a[2] = 1,2

在a[2] = 1的情況下a[3] = 1, 2, 3, 在a[2] = 2的情況下a[3] = 1, 2, 3, 4 (不能等於5及以上,否則無法構成4)

然後我們想決定a[4]的選擇取決於什麼,設s = a[1] + a[2] + a[3], 意味著前3個最多可以構成s

同時還意味著前三個可以構成[1, s],

因為a[4] >= a[3],這是我們排序的前提,

若我們取a[4] = a[3],此時前四個可以構成[1, s + a[3]],

(s+1到s+a[3]-1的值方法: 設要構成的數為x,先選全部的數,值為s+a[3],然後去掉s+a[3]-x,去掉的這個數範圍為[1, a[3] - 1],這個範圍在[1, s]之內,可以在之前的3個數中選)

所以這個a[3]就是下限了!

我們再想想剛才那個判斷下限的過程,一個特殊點在於區間[1, a[3] - 1]包含於[1, s]

前者與a[4]的選擇有關!!!

前者實際上就是[1, a[4]], 為了滿足上述區間包含的關係,a[4]最多可以為s+1!

所以a[4]的取值範圍就是[a[3], s + 1]

 

不只是a[4],我們上述過程其實呈現了一個歸納的過程,上述結論可以擴充套件到

對於滿足題意的有序陣列a,設$\displaystyle s = \sum_{j=1}^i a[j]$,一定有$\displaystyle a[i] \leq a[i+1] \leq s+1$

檢查滿不滿足即可

 

程式碼:

#include<bits/stdc++.h>
using namespace std;
int a[1000 + 10];
int main(){
    int n, m;
    scanf("%d %d", &n, &m);
    for(int i = 1; i <= n; i++){
        scanf(
"%d", &a[i]); } sort(a+1, a+1+n); int tmp = 0; for(int i = 1; i <= n; i++){ if(a[i] <= tmp+1){ tmp += a[i]; } else break; } if(tmp >= m)printf("YES"); else printf("NO"); return 0; }