Codeforces Beta Round #95 (Div. 2) E : Yet Another Task with Queens
問題概要
N*N(N<10^5)のチェス盤にM(<10^5)のクイーンが配置されている。各クイーンに対して、範囲に含められているクイーンの数を数え、その分布を出力する問題。
解法
縦、横、斜め*2について独立に考える。例えば縦での衝突を考えるとき、列の違うクイーンはまったく関与しない。同じ列のクイーンを集めてソートしてやると、端のクイーンだけは1つのクイーンの範囲に含まれ、それ以外は2つのクイーンに含まれることが分かる。これを真面目にカウントするだけ。計算量もM*log M程度で抑えられていることが少し考えれば分かる。
practiceで通ったコード
計算量O(N + M*log M)くらい。
#include <cstdio> #include <vector> #include <algorithm> using namespace std; const int MAX_N = 100000; int ts[9]; int N, M; int ds[MAX_N]; pair<int,int> ps[MAX_N]; //(x, y) void count(vector< vector<pair<int,int> > >& vs){ const int L = vs.size(); for(int i=0; i<L; i++){ if(vs[i].size() >= 2){ ds[vs[i][0].second]++; ds[vs[i].back().second]++; for(int k=1, M=(int)vs[i].size() - 1; k<M; k++){ ds[vs[i][k].second] += 2; } } } } void solve(){ //横方向 { vector< vector< pair<int,int> > > vs(N); //(x座標, id) for(int i=0; i<M; i++){ vs[ps[i].second].push_back(make_pair(ps[i].first, i)); } for(int i=0; i<N; i++){ sort(vs[i].begin(), vs[i].end()); } count(vs); } //縦方向 { vector< vector< pair<int,int> > > vs(N); //(y座標, id) for(int i=0; i<M; i++){ vs[ps[i].first].push_back(make_pair(ps[i].second, i)); } for(int i=0; i<N; i++){ sort(vs[i].begin(), vs[i].end()); } count(vs); } //斜め1 { vector< vector< pair<int,int> > > vs(2*N-1); //(y座標, id) for(int i=0; i<M; i++){ int x = ps[i].first, y = ps[i].second; vs[x+y].push_back(make_pair(y, i)); } for(int i=0; i<2*N-1; i++){ sort(vs[i].begin(), vs[i].end()); } count(vs); } //斜め2 { vector< vector< pair<int,int> > > vs(2*N-1); //(y座標, id) for(int i=0; i<M; i++){ int x = ps[i].first, y = ps[i].second; vs[x+(N-y-1)].push_back(make_pair(y, i)); } for(int i=0; i<2*N-1; i++){ sort(vs[i].begin(), vs[i].end()); } count(vs); } for(int i=0; i<M; i++){ ts[ds[i]]++; } //output for(int i=0; i<9; i++){ printf("%d%c", ts[i], i==8?'\n':' '); } } int main(){ scanf("%d%d", &N, &M); for(int i=0; i<M; i++){ int x, y; scanf("%d%d", &x, &y); x--; y--; ps[i] = make_pair(x, y); } solve(); return 0; }