SRM496 Div1 Medium(500) OneDimensionalBalls
速さは高々secondPicture.size()通り。速さを決めたとき、firstPictureとsecondPictureをソートして上下に並べ同一のボールになりうる組み合わせに線を引くと、
/\/\……\/
こんな感じの折れ線に分解できる。
/\/\……/\
ならばfirstとsecondの組み合わせの選び方はこの折れ線が含むsecondの要素数。
/\/\……\/ と \/\/……/\
なら1通り。
\/\/……\/
なら0通り。これを掛け合わせるとその速さでのボールの組み合わせの総数が得られる。
#include <vector> #include <set> using namespace std; class OneDimensionalBalls{public: long long countValidGuesses( vector <int> firstPicture, vector <int> secondPicture ) { set<int> speed; for ( int i=0; i<(int)secondPicture.size(); i++ ) if ( secondPicture[i] != firstPicture[0] ) speed.insert( abs(secondPicture[i]-firstPicture[0]) ); long long ans = 0; for ( set<int>::iterator it=speed.begin(); it!=speed.end(); it++ ) { set<int> ball[2] = { set<int>(firstPicture.begin(),firstPicture.end()), set<int>(secondPicture.begin(),secondPicture.end()) }; long long t = 1; while ( !ball[0].empty() || !ball[1].empty() ) { int f; if ( ball[1].empty() || !ball[0].empty() && *ball[0].begin() < *ball[1].begin() ) f = 0; else f = 1; int p = *ball[f].begin(); int c = 0; do { ball[f].erase(p); f = 1-f; p += *it; c++; } while ( ball[f].count(p) > 0 ); if ( f == 0 && c%2 == 1 ) t *= (c+1)/2; // /\……/\ if ( f == 1 && c%2 == 1 ) t *= 0; // \/……/\ } ans += t; } return ans; }};