TCO '09 Round2 Medium ExtendableTriangles
問題概要
nxm個の長方形に並んだ格子点があり、
点のそれぞれの色が'R','G','B'のいずれかである。
異なる3点を結んでできる三角形(三点が同一直線上にあってもよい)のうち、
3点の色が異なる三角形を「美しい」三角形と呼ぶ。
美しい三角形のうち、「二辺を共有する美しい三角形で、面積が真により大きなものがある」三角形は「拡大可能」であるという。
拡大可能な三角形の数を求めよ。
制約条件
n,m≦50
方針
美しい三角形の総数は('R'の点の数)x('G'の点の数)x('B'の点の数)になる。
そこから拡大可能でない美しい三角形(以下極大三角形)の数を引けばよい。
極大三角形の数を、愚直に求めようとすると
三角形を全列挙しなければならないのでO(2500^3/6)の時間がかかってTLE.
極大三角形の各頂点は、色ごとに列または行の両端になることに注目する。
すると頂点の候補が200x200x200に減り全探索できる。
ソースコード
int A(pi a,pi b,pi c){ int x=b.first-a.first,X=c.first-a.first; int y=b.second-a.second,Y=c.second-a.second; return abs(x*Y-y*X); } int area[200][200][200]; int maxRG[200][200],maxGB[200][200],maxRB[200][200]; class ExtendableTriangles { public: int getCount(vector <string> grid) { int h=grid.size(),w=grid[0].size(); int cnt[3]={}, tonum[256]; tonum['R']=0; tonum['G']=1; tonum['B']=2; vector<pi> P[3]; rep(i,h)rep(j,w){ int c=tonum[grid[i][j]]; cnt[c]++; int y=i-1,Y=i+1,x=j-1,X=j+1; for(;y>=0&&grid[y][j]!=grid[i][j];)y--; for(;x>=0&&grid[i][x]!=grid[i][j];)x--; for(;Y<h&&grid[Y][j]!=grid[i][j];)Y++; for(;X<w&&grid[i][X]!=grid[i][j];)X++; if(y<0||Y>=h||x<0||X>=w)P[c].pb(mp(i,j)); } rep(i,3){ sort(all(P[i])); P[i].erase(unique(all(P[i])),P[i].end()); } rep(i,200)rep(j,200)maxRG[i][j]=maxRB[i][j]=maxGB[i][j]=0; rep(r,P[0].size())rep(g,P[1].size())rep(b,P[2].size()){ area[r][g][b]=A(P[0][r],P[1][g],P[2][b]); maxRG[r][g]=max(maxRG[r][g],area[r][g][b]); maxRB[r][b]=max(maxRB[r][b],area[r][g][b]); maxGB[g][b]=max(maxGB[g][b],area[r][g][b]); } ll ans=(ll)cnt[0]*cnt[1]*cnt[2]; rep(r,P[0].size())rep(g,P[1].size())rep(b,P[2].size()) if(maxRG[r][g]==area[r][g][b]&& maxGB[g][b]==area[r][g][b]&& maxRB[r][b]==area[r][g][b])ans--; return ans; } };