Codeforces Round #249 (Div. 2) D. Special Grid

来源:互联网 发布:vp矢量化软件 编辑:程序博客网 时间:2024/05/23 00:04

先预处理出每个点向8个方向延伸最长能延伸多远,然后依次枚举每个点,处理出以这个点为顶点的合法三角形数有多少个,这样每个合法三角形就被算了3次,最后答案除3。题目条件对每个三角形有很强的限制,对于枚举的每个点,一次向8个方向枚举,这样得到三角形的一条边,确定一条边后另一个点的选择不多,只要一一检查就可以了。复杂度最坏O(n^3)

#include <cstdio>#include <cstring>#include <algorithm>#define maxn 409using namespace std;int dp[maxn][maxn][8],n,m;char s[maxn][maxn];int dx[]={-1,-1,0,1,1,1,0,-1};int dy[]={0,1,1,1,0,-1,-1,-1};int dfs(int x,int y,int z){int &ans=dp[x][y][z];if(ans!=-1)return ans;if(x>n||y>m||x<1||y<1)return ans=0;if(s[x][y]=='1')return ans=0;if(z==0){return ans=1+dfs(x-1,y,0);}else if(z==1){return ans=1+dfs(x-1,y+1,1);}else if(z==2){return ans=1+dfs(x,y+1,2);}else if(z==3){return ans=1+dfs(x+1,y+1,3);}else if(z==4){return ans=1+dfs(x+1,y,4);}else if(z==5){return ans=1+dfs(x+1,y-1,5);}else if(z==6){return ans=1+dfs(x,y-1,6);}else{return ans=1+dfs(x-1,y-1,7);}}int main(){memset(dp,-1,sizeof(dp));scanf("%d%d",&n,&m);for(int i=1;i<=n;i++)scanf("%s",s[i]+1);for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) for(int k=0;k<8;k++) dfs(i,j,k);__int64 ans=0;for(int i=1;i<=n;i++){for(int j=1;j<=m;j++){if(s[i][j]=='1')continue;int cur=0;for(int k=0;k<8;k++){if(k%2==0){for(int p=1;p<dp[i][j][k];p++){int nk=((k-2)%8+8)%8;if(dp[i][j][nk]>p&&dp[i+p*dx[nk]][j+p*dy[nk]][(nk+3)%8]>p)cur++;nk=((k-1)%8+8)%8;if(dp[i][j][nk]>p&&dp[i+p*dx[nk]][j+p*dy[nk]][(nk+3)%8]>p)cur++;if(p%2==0){nk=((k-1)%8+8)%8;if(dp[i][j][nk]>p/2&&dp[i+p/2*dx[nk]][j+p/2*dy[nk]][(nk+2)%8]>p/2)cur++;}}}else{for(int p=1;p<dp[i][j][k];p++){int nk=((k-2)%8+8)%8;if(dp[i][j][nk]>p&&dp[i+p*dx[nk]][j+p*dy[nk]][(nk+3)%8]>p*2)cur++;nk=((k-1)%8+8)%8;if(dp[i][j][nk]>p&&dp[i+p*dx[nk]][j+p*dy[nk]][(nk+2)%8]>p)cur++;nk=((k-1)%8+8)%8;if(dp[i][j][nk]>p*2&&dp[i+2*p*dx[nk]][j+2*p*dy[nk]][(nk+3)%8]>p)cur++;}}}ans+=cur;}}printf("%I64d\n",ans/3);//system("pause");return 0;}



0 0