SEU寒假训练题解二 H Codeforces 435D

题意

数等腰直角三角形个数,要求顶点无黑点,边上无黑点。














题解

作为一个暴力计数问题,一个很重要的思想是不重复不遗漏。

这样想到每个点作为直角顶点的话有八种形态,不同直角顶点的三角形显然不是相同的直角三角形。这样只要枚举完直角顶点后,再枚举直角边长/斜边上的高就好了。

然后就是如何判断黑点的问题,解决方案就是前缀和。

和输入一样黑取1,白取0,(我觉得这确实算一个提示。。。)计算横竖两条对角线四个前缀和。然后只要O(1)就能判定是否有黑点


于是

一个O(n^3)的做法就有了。


好了剩下的问题就是编程代码问题,包括各种边界判定啦神马的,不过考虑到八种形态的旋转对称性,三角形旋转不好弄,矩形旋转简单啊,运动是相对的。。。

可以用旋转矩阵的方法去做,这样代码难度和长度都可以接受了。

不过我个逗比居然把旋转写成了转置。。。查了好久。。。OTZ

















#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <string.h>
#include <string>
#include <map>
#include <set> 
using namespace std;

int Matrix [405][405];

int temp[405][405];
void rotate(int n, int m) {
    memset(temp, 0, sizeof(temp));
    for(int i = 1; i <= n; i++) {
        for(int j = 1; j <= m; j++) {
            temp[j][n - i + 1] = Matrix[i][j];
        }
    }
    memcpy(Matrix, temp, sizeof(temp));
}
void Read(int &a){
    char ch;
    a = 0;
    ch = getchar();
    while( !(ch >= '0' && ch <= '9') ) ch = getchar();
    while((ch >= '0' && ch <= '9') ){
        a = a * 10 + ch - '0';
        ch = getchar();
    }
}
int row[405][405],col[405][405],dia1[405][405],dia2[405][405];
long long cal(int m,int n)
{
    memset(row,0,sizeof(row));
    memset(col,0,sizeof(col));
    memset(dia2,0,sizeof(dia1));
    memset(dia1,0,sizeof(dia2));
    for (int i=1;i<=m+1;i++)
        for (int j=1;j<=n+1;j++)
        {
            row[i][j]=row[i][j-1]+Matrix[i][j];
            col[i][j]=col[i-1][j]+Matrix[i][j];
            dia1[i][j]=dia1[i-1][j-1]+Matrix[i][j];
            dia2[i][j]=dia2[i-1][j+1]+Matrix[i][j];
        }
    long long cnt=0;
    for (int i=1;i<=m;i++)
        for (int j=1;j<=n;j++)
        {
            if (Matrix[i][j]) continue;
            for (int k=1;k<min(i,j);k++)
            {
                if ((row[i][j]-row[i][j-k-1]==0)&&(col[i][j]-col[i-k-1][j]==0)&&(dia2[i][j-k]-dia2[i-k-1][j+1]==0))
                    cnt++;
                if (j+k<=n)
                    if ((row[i-k][j+k]-row[i-k][j-k-1]==0)&&(dia1[i][j]-dia1[i-k-1][j-k-1]==0)&&(dia2[i][j]-dia2[i-k-1][j+k+1]==0))
                        cnt++;
            }
        }
    return cnt;            
}


int main()
{
	//freopen("input","r",stdin);
	//freopen("output","w",stdout);
    int m,n;
    Read(m),Read(n);
    for (int i=1;i<=m;i++)
        for (int j=1;j<=n;j++)
        {
            char ch=getchar();
            if (ch=='\n') ch=getchar();
            Matrix[i][j]=ch-'0';
        }
    /*for (int i=0;i<m;i++)
            for (int j=0;j<n;j++)
                cout<<Matrix[i][j]<<endl;*/
    long long ans=0;
    ans+=cal(m,n);
    rotate(m,n);
    ans+=cal(n,m);
    rotate(n,m);
    ans+=cal(m,n);
    rotate(m,n);
    ans+=cal(n,m);
    cout<<ans<<endl;
	return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值