[ABC347C] Ideal Holidays題解

adsd45666發表於2024-03-31

[ABC347C] Ideal Holidays題解

原題傳送門

原題傳送門(洛谷)

​ 題意翻譯:

​ 在 \(AtCoder\) 王國中,一個周有 \(A+B\) 天。其中在一週中, \([1,A]\) 天是假日, \([A+1,B]\) 天是工作日。

​ 高橋有 \(N\) 個計劃,第 \(i\) 個計劃安排在 \(i\) 天后。他不知道今天是周幾,但他想知道是否能將計劃都安排在假期中;

​ 若可以則列印Yes,否則列印No

​ 題意解釋:

如下圖,黃綠色的是假期,紅色的是假期。

高橋的安排在這個區間中,對此我們可以進行一個狀態壓縮,也就是把所有的天數對 \(A+B\) 取模,壓縮到一個周內;

即:

int sum=a+b;                 //儲存A+B
for(int i=1;i<=n;i++){     
	scanf("%d",d[i]);        //輸入
    d[i]%=sum;               //壓縮到一週內
}

若有大於 \(A\) 的,便輸出No ,於是我們可以寫出第一版程式碼:

#define seq(q, w, e) for (int q = w; q <= e; q++)
#define ll long long
using namespace std;
const int maxn = 2e5+10;
ll n,a,b,sum,num;
ll d[maxn];
signed main()
{
    scanf("%lld",&n);
    scanf("%lld%lld",&a,&b);
    sum=a+b;
    seq(i,1,n){
        scanf("%lld",&num);
        d[i]=num%sum;
    }
    seq(i,1,n){
        if(d[i]>a){
            printf("No");
            return 0;
        }
    }
    printf("Yes");
    return 0;
}

但是會發現錯的有點多,這是為啥呢?

我們可以看到,由於高橋不知道今天是周幾,所以直接比較行不通。


於是我們想到第二種思路:

用其中最大值減最小值,即求一個區間,看這個區間是否在 \(A\) 以內即可。

即可寫出第二版程式碼:

#define seq(q, w, e) for (int q = w; q <= e; q++)
#define ll long long
using namespace std;
const int maxn = 2e5+10;
ll n,a,b,sum,num;
ll d[maxn];
signed main()
{
    scanf("%lld",&n);
    scanf("%lld%lld",&a,&b);
    sum=a+b;
    seq(i,1,n){
        scanf("%lld",&num);
        d[i]=num%sum;
    }
    sort(d+1,d+1+n);
    num=d[n]-d[1]+1;              //區間值
    if(num>a){                    //區間不在A之內
        printf("No");
        return 0;
    }
    printf("Yes");
    return 0;
}

但還是會錯一個點,這又是為啥呢?

因為如果其跨度超過 \(B\) 我們可以放到下週去做。

​ 如: 使 \(A=2,B=5,N=2,D[]=\{1,7\}\) 對與我們第二種做法,區間值應為 \(7\)\(7>A(2)\) ,應輸出No

但如果我們假設今天是週一,第一個計劃在本週二實現,第二個計劃在下週一實現的話,其實是可行的。


為了解決上面的問題,我們要分類討論一下:

  1. \(sum<=A\) 絕對可以實現,直接輸出Yes;

  2. \(sum>A\) :

    1.若相鄰兩個元素的差有一個大於 \(B\) 則可以實現,直接輸出Yes

    ​ (按大小排序,且區間在 \([A,A+B]\) 之間,如果有一個差大於 \(B\) ,則後面的元素於此元素的差都大於 \(B\) )

    2.若相鄰兩個元素的差都小於 \(B\) 則不可以實現,輸出No

根據上面的分析,我們可在二思路上改進一下,即可得出正確程式碼:

#define seq(q, w, e) for (int q = w; q <= e; q++)
#define ll long long
using namespace std;
const int maxn = 2e5+10;
ll n,a,b,sum;
ll d[maxn];
signed main()
{
    scanf("%lld",&n);
    scanf("%lld%lld",&a,&b);
    sum=a+b;
    seq(i,1,n){
        scanf("%lld",&d[i]);
        d[i]%=sum;
    }
    sort(d+1,d+1+n);
    sum=d[n]-d[1]+1;
    if(sum>a){                      //區間不在A之內
        seq(i,1,n-1){
            if(d[i+1]-d[i]-1>=b){   //若有一個差大於B
                printf("Yes");
                return 0;
            }
        }
        printf("No");
        return 0;
    }
    printf("Yes");
    return 0;
}

總的來說,本題對做題者的細心程度非常考察,本蒟蒻在做時吃了九遍罰時,在此感謝 @LiJoQiao 前輩提供思路。

相關文章