公式

C - Sneaking Glances 解説 by en_translator


A greedy strategy of moving in negative direction if you are at a positive direction, and in positive if at negative, is wrong.
For example, when \(L=(40,50,90,1,1,1)\), this greedy algorithm allows to pass through coordinate \(0\) three times, but choosing negative, negative, and positive as the first moves allows \(5\) times.


Let us use the fact that \(N\) is small.
When there are \(N\) binary choices (positive or negative), for a total of \(2^N\) combination, it is convenient to use the bitwise exhaustive search (Explanation (in Japanese))

  • For \(i=0,1,\dots,2^N-1\), do the following.
    • For \(j=0,1,\dots,N\), if the binary representation of \(i\) has \(0\) as its \(2^j\)s place, move in the negative direction; if it has \(1\), move in positive.

During the simulation, using the value \(0.5\) is inconvenient; multiplying all the coordinates and moving distance by \(2\) allows us to handle everything within integers.
That is, assume that we start at coordinate \(1\) and move by distance \(2L_i\).
Also, one can determine if you pass through \(0\) by checking if \(xy<0\), where \(x\) and \(y\) are the coordinates before and after a move. Directly using this formula may lead to an overflow, so it is recommended to compress each value to \(-1\), \(0\), or \(1\) before evaluating it.

The time complexity is \(O(2^N N)\).

Sample code (C++):

#include<bits/stdc++.h>

using namespace std;
using ll=long long;

ll sgn(ll x){
  if(x>0){return 1;}
  else if(x<0){return -1;}
  return 0;
}

int main(){
  ll n;
  cin >> n;
  vector<ll> l(n);
  for(auto &nx : l){
    cin >> nx;
    nx*=2;
  }
  ll best=0;
  for(ll i=0;i<(1ll<<n);i++){
    ll pos=1,cur=0;
    for(ll j=0;j<n;j++){
      ll npos=pos;
      if(i&(1ll<<j)){npos+=l[j];}
      else{npos-=l[j];}
      if(sgn(pos)*sgn(npos)<0){cur++;}
      pos=npos;
    }
    best=max(best,cur);
  }
  cout << best << "\n";
  return 0;
}

投稿日時:
最終更新: