题解 CF1764E 【Doremy's Number Line】
VinstaG173 · · 题解
fk u corner case.
贪心+分类讨论。鸣谢 Spasmodic 的 hack 数据帮我找到原贪心的错误点。
对于一个数
注意到染色方法中所有限制条件都是不超过某个数即可染色,则对于“期望染成任意颜色”的点,若
接下来考虑
对于情况 4,此时只要将
注意到
发现某时刻能够操作的颜色在
接下来我们认为对于
因此最终操作序列必然为
综上,我们得到贪心策略:
- 对于颜色
1 判断是否符合情况 1,2,3,若为情况 4 则将k 变为k-b_1 ; - 将颜色
2,3,\dots,n 按a_i+b_i 从大到小排序; - 对于排序后的序列,每次取出
a_i+b_i 最大且没有操作过的颜色,判断是否符合情况 1,2,3,若为情况 4 则将k 变为k-b_i ,重复进行这一步。
但是很遗憾,这样的贪心策略是错误的。以下是 Spasmodic 提供的 hack 数据:
3 141
140 1
50 90
99 50
对于这组数据,我们直接以 NO。
但是我们发现若先操作颜色 YES。
分析一下我们会发现问题出在最后的结论:对于
事实上这个结论在几乎所有情况下都是正确的,只有在一种情况下会出错,就是只剩下
这个错误出现的本质原因是情况 4 对于最后一种未染的颜色的后续不是进行操作,而是直接判定为 NO 并结束。因此若只剩下两种颜色可染,操作其中一种颜色后另一种颜色将不能被操作,“随着
这个错误的解决方案也很简单,由于只剩两种颜色,我们将它们的优先顺序调换后再做一次相同的贪心,只要有一次判定为 YES 即成功,否则判定为 NO。
时间复杂度瓶颈在排序的
Code:
int n,k,_k;
int id[100003];
int a[100003],b[100003];
inline int cmp(int x,int y){
if(a[x]+b[x]==a[y]+b[y])
return b[x]>=b[y];
return a[x]+b[x]>a[y]+b[y];
}void solve(){rd(n);rd(k);
for(rg int i=1;i<=n;++i){
rd(a[i]);rd(b[i]);id[i]=i;
}if(k<=a[1]){puts("YES");return;}
if(k<=b[1]){puts((n>1)?"YES":"NO");return;}
if(k>a[1]+b[1]){puts("NO");return;}
k-=b[1];_k=k;sort(id+2,id+n+1,cmp);
for(rg int _i=2,i;_i<=n;++_i){
i=id[_i];if(a[i]+b[i]<k)break;
if(k<=a[i]){puts("YES");return;}
if(k<=b[i]&&_i<n){puts("YES");return;}
k-=b[i];
}if(n>2){id[n-1]^=id[n]^=id[n-1]^=id[n];k=_k;
for(rg int _i=2,i;_i<=n;++_i){
i=id[_i];if(a[i]+b[i]<k)break;
if(k<=a[i]){puts("YES");return;}
if(k<=b[i]){puts((_i<n)?"YES":"NO");return;}
k-=b[i];
}}puts("NO");
}