第18回ABC C問題「菱型カウント」


C: 菱型カウント - AtCoder Beginner Contest #018 | AtCoder

解法:30点解法を枝刈りする
O(RCN)(Nはxの数)ぐらいになるので、Nが300以下ぐらいのケースに対して枝刈りを適用すると時間内に解くことができる。
枝刈りは
・確実に範囲外になってしまう座標(計算が結構めんどくさい)
・近くにxが無い座標
どちらかの条件を満たす場合に行う。

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <math.h>
#include <vector>
#include <queue>
#include <algorithm>
#include <sstream>
#include <string>

using namespace std;

#define FOR(I,N) for(int I = 0; I < (int)(N); I++)
#define FIN(V) cout<<V<<endl
#define pb push_back
#define INF (1 << 30)

typedef pair<int, int> P;

string sValueOf(int v){stringstream ss;ss<<v;return ss.str();}
int parseInt(string v){int i;stringstream ss(v);ss>>i;return i;}
void fast_io() {cin.tie(0); ios::sync_with_stdio(false);}

int map[504][504];
int h,w,k;

vector<P> black;

int main(){
	int i,j,m,l;
	cin>>h>>w>>k;
	fill_n(*map,504*504,1);
	string in;
	FOR(i,h){
		cin>>in;
		FOR(j,w){
			char c = in[j];
			if(c=='o'){
				map[j+1][i+1] = 0;
			}else{
				map[j+1][i+1] = 1;
				black.pb(P(j+1,i+1));
			}
		}
	}
	int ans = 0;
	int dis = 2*k-1;
	int size = black.size();
	FOR(i,h)FOR(j,w){
		int x = j+1;
		int y = i+1;
		if(j<k-1)continue;
		if(w-j<=k-1)continue;
		if(h-i<=dis-1)continue;

		if(size<=300){
			int cy = y+k-1;
			double mini = INF;
			FOR(m,size){
				mini = min(mini,sqrt(pow(black[m].first-x,2.0)+pow(black[m].second-cy,2.0)));
			}
			if(mini>k){ans++;continue;}
		}

		int width = 1;
		bool able = true;
		FOR(m,dis){
			if(map[x][y+m]){able = false;break;}
		}
		if(!able)continue;
		FOR(m,dis){
			FOR(l,width){
				if(map[x+l][y]){able = false;break;}
			}
			if(!able)break;
			y++;
			if(m>=k-1){///後半
				x++;
				width-=2;
			}else{
				x--;
				width+=2;
			}
		}
		if(able){
			ans++;
		}
	}

	cout<<ans<<endl;
	return 0;
}