题解:P16434 [APIO 2026 中国赛区] 蛋糕
卡帕瓦_KAPawa · · 题解
一.前言
还得加练思维水平了。由于怕被虐并没有参加 APIO。当天晚上看到一大堆 T2 建议降蓝贴和 T2 AC 的犇犇,遂飞速阅读了 T2 题面并思考做法。到 AC 共用了
二.题面简述
你的任务是猜出评测机里的一个数。为此你需要构造一个长 最大 为
三.思路详解
以下为方便书写,规定
subtask 1:
不难发现
期望得分
:::success[代码]
std::vector<int> bake_cakes(int N, int W, int K){
std::vector<int> qst;
if(K==100) for(int i=1;i<=100;i++) qst.push_back(i);
return qst;
}
int find_tastiness(int m, int W, int K){
std::vector<int> s1,s2;
if(K==100){
for(int i=0;i<m;i++){
s1.push_back(i),s2.push_back(i+1);
int op=compare_tastiness(s1,s2);
if(op==0) return i+1;
s1.clear(),s2.clear();
}
}
return 0;
}
:::
subtask 2:
因为评测机给出的信息只有
- 假设
d=1 ,那么\sum_{i\in S_1}a_i=1+1+2=4<5 。 - 假设
d=2 ,那么\sum_{i\in S_1}a_i=2+1+2=5=5 。 - 假设
d=3 ,那么\sum_{i\in S_1}a_i=3+1+2=6>5 。
期望得分
:::success[代码]
std::vector<int> bake_cakes(int N, int W, int K){
std::vector<int> qst;
if(K==1) qst.push_back(1),qst.push_back(2),qst.push_back(5);
return qst;
}
int find_tastiness(int m, int W, int K){
if(K==1){
s1.push_back(0),s1.push_back(1),s1.push_back(2),s2.push_back(3);
int op=compare_tastiness(s1,s2);
if(op==1) return 3;
else if(op==0) return 2;
else return 1;
}
return 0;
}
:::
相似的,我们还可以从 位置上 考虑。我们构造
- 假设
d=1 ,那么\sum_{i\in S_1}a_i=1+2=3<4 。 - 假设
d=2 ,那么\sum_{i\in S_1}a_i=2+2=4=4 。 - 假设
d=3 ,那么\sum_{i\in S_1}a_i=2+3=5>4 。
这本质上是找三个数
接着重新考虑。我们可以让这些数 首尾配对。构造
- 假设
d=1 ,那么\sum_{i\in S_1}a_i=1+3=4 ,\sum_{i\in S_2}a_i=1+2=3 ,4>3 。 - 假设
d=2 ,那么\sum_{i\in S_1}a_i=1+3=4 ,\sum_{i\in S_2}a_i=2+2=4 ,4=4 。 - 假设
d=3 ,那么\sum_{i\in S_1}a_i=1+3=4 ,\sum_{i\in S_2}a_i=2+3=5 ,4<5 。
这本质上是说最小的数和最大的数都是确定的,所以我们通过查看中间的数的大小来查确定给出的数。
代码就不放了。
subtask 3:
容易发现
很容易想到一个性质:
所以在
那么让 显然我比较唐绕了半天弯,并想到了第一步可以二分,成功让思考时间
不难发现我们做第一步的时候从高到低遍历,第一个满足返回值是
期望得分
:::success[代码]
std::vector<int> bake_cakes(int N, int W, int K){
std::vector<int> qst;
if(K==30){
for(int i=29;i>=0;i--) qst.push_back(1<<i);
qst.push_back(1);
}
return qst;
}
int find_tastiness(int m, int W, int K){
std::vector<int> s1,s2;
if(K==30){
int pos=0;
for(int i=29;i>=0;i--){
for(int j=0;j<i+1;j++) s1.push_back(j);
s2.push_back(i+1);
int op=compare_tastiness(s1,s2);
if(op==0){pos=i+1;break;}
s1.clear(),s2.clear();
}
s1.clear(),s2.clear();
s1.push_back(pos),s2.push_back(pos+1);
int ans=1<<(pos-1);
for(int i=pos-1;i>=1;i--){
s1.push_back(i);
int op=compare_tastiness(s1,s2);
if(op==1) s1.pop_back();
else if(op==0){ans|=(1<<(i-1));break;}
else ans|=(1<<(i-1));
}
return ans;
}
}
:::
subtask 4:
容易发现
考虑三分。设
唯一的问题是:
尝试沿用 subtask
特判最后的一次三分可以减少分讨量。
期望得分
:::success[代码]
std::vector<int> bake_cakes(int N, int W, int K){
std::vector<int> qst;
if(K==7) for(int i=1;i<=2200;i++) qst.push_back(i);
return qst;
}
int find_tastiness(int m, int W, int K){
std::vector<int> s1,s2;
if(K==7){
int l=1,r=2187;
while(l<r-2){
s1.clear(),s2.clear();
int mid1=l+(r-l+1)/3,mid2=r-(r-l+1)/3;
int tot=(r-l+4)/6;
for(int i=0;i<tot;i++){
s1.push_back(l+i-1),s1.push_back(r-i);
s2.push_back(l+i-1+tot),s2.push_back(r-i-tot);
}
int op=compare_tastiness(s1,s2);
if(op==-1) l=mid2+1;
else if(op==0) l=mid1,r=mid2;
else r=mid1-1;
}
s1.clear(),s2.clear();
s1.push_back(l-1),s1.push_back(r);
s2.push_back(l),s2.push_back(r-1);
int op=compare_tastiness(s1,s2);
if(op==-1) return r;
else if(op==0) return l+1;
else return l;
}
}
:::