AGC053D Everyone is a winner
Description
有 个人一起做题,每个人有 个题目需要 分钟完成, 道两分钟题, 道三分钟题。判定在每个人任意选择做题顺序的情况下,是否可能 第 个人是完成前 到题目最快的人(之一)。
Solution
如果确定每个人前 个数字的 分配 ,那么显然在前 题以及后 题都会是按照耗时倒序做
考虑维护序列 ,其中 表示对第 个人前 道题目完成时间的限制,初始化为每个人都按耗时倒序做题时所需要花费的时间的最小值。
倒序处理每个人调整策略后对前缀的影响,即处理到 时 为 中每个人调整策略后做前 题的时间以及 中每个人完全倒序做题的时间中的最小值。此时需要调整 倒序做题的策略来使得用时
设 完成的前 个题目中 分钟题的数量分别为 ,于是有 。那么要在最大化 的基础上最大化 。无解判据即找不到这样的
得到合法方案之后再去更新前缀 的 。
一个比较明显的问题没有处理 的对子 中 对 的影响。官方题解中的证明,大意是如果经过 的策略调整后 于是后面 的折线斜率不超过 ,于是如果抛去 后用时为 的题目过多一定会在处理 的时候影响到。
这个做法看起来是 的,但是每个人做题的耗时本质上是折线,而更新前缀的过程中也是让折线和折线取 。这条折线也非常特殊,斜率只有 三种,那么可以维护每个 中的 而询问折线某处取值就是代入表达式取 。上面提到的取 操作即将两条折线的 对位取
寻找 的合法值时可以从 向下暴力枚举取值,总枚举量是 的。合法性等价于是否存在 满足 另外的两条限制加在 上,可以根据 而 是定值得到 关于 的表达式。
前缀折线的表达式据 可以得到。
复杂度为
Code
const int N=2e5+10,inf=0x3f3f3f3f;
int n,a[N],b[N],c[N];
struct Line{
int a,b,c;
//K=1,2,3 时对应的截距
Line(){a=b=c=inf;}
Line(int x,int y,int z){a=x; b=y; c=z; return ;}
inline int at(int x){return min({a+x,b+2*x,c+3*x});}
};
inline Line Merge(Line a,Line b){return Line(min(a.a,b.a),min(a.b,b.b),min(a.c,b.c));}
int main(){
int T=read();
while(T--){
n=read();
Line A;
rep(i,1,n){
a[i]=read(),b[i]=read(),c[i]=read();
A=Merge(A,Line(b[i]+2*c[i],c[i],0));
}
bool illegal=0;
for(int i=n;i>=1;--i){
int v=A.at(i);
while(v>=0){
int lhs=min(a[i],min((3*i-v)/2,c[i]+2*i-v));
int rhs=max(0,max(2*i-v,(3*i-v-b[i]+1)/2));
if(lhs>=rhs) break;
--v;
}
if(v<0){
illegal=1;
break;
}
int x=min(a[i],min((3*i-v)/2,c[i]+2*i-v));
int B=3*i-v-2*x,C=v+x-2*i;
A=Merge(A,Line(B+2*C,C,0));
}
puts(illegal?"No":"Yes");
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律