Catch a Rabbit with Changing Moods
Autumn Tournament (2021)
Submission name: rabbit.cpp
Problem summary
A rabbit starts in an unknown cell of a row1..N. Each second inspect one cell, catching it if present. Otherwise it moves: for S scared seconds it moves away from the inspection, staying put at a boundary; for C curious seconds it moves one cell toward the inspection. These moods repeat. Produce a short fixed inspection sequence guaranteeing capture from every starting cell.
Source clarification. The source permits S=C=0 numerically but does not define its movement schedule. The intended analysis assumes S+C>0.
Input
N S C.
Output
K followed by K inspected cells in1..N. Repetition is allowed; the checker accepts any valid sequence within scoring limits.
Constraints
2≤N≤10000; 0≤S,C≤50. A nonempty mood cycle requires S+C>0; the printed bounds omit that condition.
Worked example
New worked example; valid constructive answers may differ.
Input
4 0 1
Output
3 2 3 3
Solution analysis
- Track all possible uncaught positions, not one rabbit. The strategy keeps them in one or two intervals. Remove the inspected position before applying the deterministic movement. Curious movement pulls endpoints inward; scared movement pushes them away, clipped to1..N.
- If C≥S, keep one interval[l,r]. On a scared second inspect l; survivors become[l+2,min(N,r+1)], with empty cases handled separately. On a curious second inspect min(r,l+1), contracting uncertainty. Inspect any remaining singleton immediately.
- If S>C, split possible starts near cell1+round(N*(S-C)/(3S)). First eliminate the right interval: on scared seconds inspect its left endpoint, on curious seconds inspect N. Update both intervals. Then eliminate the left interval, inspecting its right endpoint when scared and its left endpoint when curious.
- The split balances two sweeps. A scared right sweep eliminates roughly two candidates per scared step but may expand by one on curious steps; the left group is first pushed toward the boundary and then swept. The balancing term is N*(S+C)/(3S). For C≥S the leading term is N*(S+C)/(S+2C). Partial mood blocks are covered by the3*max(S,C) slack.
- For N=4,S=0,C=1, inspect2. The remaining possible positions become{2,3}. Inspect3, leaving only position3 after movement. Inspect3 again: every possible rabbit is caught. This is a new small worked example, not the original statement’s deliberately lower-scoring example.
- The score is zero for K>2N, full for K≤T=N*(S+C)/(S+2max(S,C))+3max(S,C), and otherwise0.3*(T/K)². This is a scored construction, not a request for a unique shortest sequence. The interval strategies are the intended full-score constructions.
Why it works
The tracked intervals initially cover every start. Each update removes exactly the inspected position and maps every survivor by the prescribed movement. A scared inspection is never strictly inside a tracked interval, so its image remains an interval; curious movement also has an interval image. Thus no uncaught rabbit is discarded incorrectly. Complete mood blocks shrink the active interval until empty. Balancing the scared-dominant sweeps gives the threshold’s leading term, with its slack covering partial blocks.
Watch out. Remove the inspected cell before movement; jumping into it afterward is not capture. Scared rabbits remain at boundaries. Two curious possibilities can collapse into one. S=C=0 has no defined mood or scoring threshold in the source; the defensive all-cells branch cannot establish a score for an undefined schedule.
Commented C++17 solution
An independently written complete program with standard headers.
#include<algorithm>
#include<cmath>
#include<iostream>
#include<vector>
using namespace std;
struct Interval{
int left;
int right;
bool empty()const{
return left>right;
}
};
int main(){
int n;
int scared;
int curious;
cin>>n>>scared>>curious;
vector<int>inspections;
if(scared+curious==0){
// The statement does not define movement for this degenerate schedule.
cout<<n<<'\n';
for(int cell=1;cell<=n;++cell){
cout<<cell<<(cell==n?'\n':' ');
}
return 0;
}
auto moveInterval=[&](Interval&interval,int shot,bool isScared){
if(interval.empty()){
return;
}
if(interval.left==interval.right&&interval.left==shot){
interval.left=1;
interval.right=0;
return;
}
if(isScared){
if(interval.left==shot){
++interval.left;
}
if(interval.right==shot){
--interval.right;
}
}
auto movePosition=[&](int position){
if(position==shot){
return position;
}
int direction=position<shot?-1:1;
if(!isScared){
direction=-direction;
}
return max(1,min(n,position+direction));
};
interval.left=movePosition(interval.left);
interval.right=movePosition(interval.right);
};
auto scaredNow=[&](){
return static_cast<int>(inspections.size())%(scared+curious)<scared;
};
if(curious>=scared){
Interval possible{1,n};
while(!possible.empty()){
bool mood=scaredNow();
int shot=mood?possible.left:min(possible.right,possible.left+1);
inspections.push_back(shot);
moveInterval(possible,shot,mood);
}
}
else{
int split=1+static_cast<int>(round(n*(scared-curious)/(3.0*scared)));
Interval left{1,split-1};
Interval right{split,n};
while(!right.empty()){
bool mood=scaredNow();
int shot=mood?right.left:n;
inspections.push_back(shot);
moveInterval(left,shot,mood);
moveInterval(right,shot,mood);
}
while(!left.empty()){
bool mood=scaredNow();
int shot=mood?left.right:left.left;
inspections.push_back(shot);
moveInterval(left,shot,mood);
}
}
cout<<inspections.size()<<'\n';
for(int i=0;i<static_cast<int>(inspections.size());++i){
cout<<inspections[i]<<(i+1==static_cast<int>(inspections.size())?'\n':' ');
}
}