[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
。
但如果我們假設今天是週一,第一個計劃在本週二實現,第二個計劃在下週一實現的話,其實是可行的。
為了解決上面的問題,我們要分類討論一下:
-
\(sum<=A\) 絕對可以實現,直接輸出
Yes
; -
\(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 前輩提供思路。