菱形内的计数 jzoj 1404 模拟+递推

17 篇文章 0 订阅
4 篇文章 0 订阅

题目大意

 教主上电视了!这个消息绝对是一个爆炸性的新闻。一经传开,大街上瞬间就没人了(都回家看电视去了),商店打烊,工厂停业。大家都把电视机的音量开到最大,教主的声音回响在大街小巷。
  小L给小X慌乱地打开自己家的电视机,发现所有频道都播放的是教主的采访节目(-_-bbb)。只见电视屏幕上的教主笑意吟吟,给大家出了一道难题:
  一个边长为n的大菱形被均匀地划分成了n*n个边长为1的小菱形组成的网格,但是网格中部分边被抹去了,小L想知道,大菱形内有多少个平行四边形,这些平行四边形内不存在边。
  教主说,如果谁写出了程序,移动用户请将程序发送到xxxx,联通用户请将程序发送到xxxx……如果答对这个题,将有机会参加抽奖,大奖将是教主签名的Orz教主T-Shirt一件!这个奖品太具有诱惑力了。于是你需要编一个程序完成这么一道题。

分析

首先将在读入时将菱形转成正方形。(自己推)
有(n+1)*(n+1)个格点,用d[i][j]表示第i行第j列的格点到第1行第j列的格点之间有多少条竖线,f[i][j]表示第i行第j条横线(被抹去的也算)在这一列上的上一条没被抹去横线的位置。

接着扫描i,j。
设h为矩形的高,初值为-1。若第i行第j根横线没被抹去,且d[i][j]-d[i-f[i][j]][j]=f[i][j]即当前横线到上一根横线的左边有封闭的竖线,那么表示这可能是一个矩形的开始,此时矩形的高h赋为f[i][j]。
若h>-1,且d[i][j]-d [i-h][j]>0即当前扫描到的段左边有若干条竖线(矩形内不为空);或f[i][j]<>h(矩形内不为空或不是矩形);或当前扫描到的横线被抹去,h赋为-1。
若h>-1且d[i][j+1]-d[i-h][j+1]=h,即横线右边线段有封闭的竖线,那么答案+1。

ps:注意细节!!!

code

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<queue>

using namespace std;

char a[2000][2000];
int f[2000][2000];

int d[2000][2000];
int h[2000][2000];

int n;

int init()
{
    scanf("%d",&n);
    int jj=n;
    for (int i=1;i<=2*n;i++)
    {
        char c=getchar();
        for (int j=1;j<=2*n;j++)
            scanf("%c",&a[i][j]);
    }
    int x=1;
    int y=n;
    for (int i=1;i<=n+1;i++)
    {
        int xx=x;
        for (int j=2;j<=n+n;j+=2)
        {
            if (a[x][y]=='/')
                f[j][i]=1;
            x++;
            y--;
        }
        x=xx+1;
        y=n+i;
    }
    x=1;
    y=n+1;
    int ii=1;
    for (int i=1;i<=n+n+1;i+=2)
    {
        int xx=x;
        for (int j=1;j<=n;j++)
        {
            if (a[x][y]!=' ')
                f[i][j]=2;
            x++;
            y++;
        }

        x=xx+1;
        y=n-ii+1;
        ii++;
    }
    x=1;
    for (int i=1;i<=n+n+1;i+=2)
    {
        int y=1;
        for (int j=1;j<=n+1;j++)
        {
            if (f[i-1][j]==1)   
                d[x][y]=d[x-1][y]+1;
            else
                d[x][y]=d[x-1][y];
            if (f[i-2][j]==2)   
                h[x][y]=x-1;
            else
                h[x][y]=h[x-1][y];
            y++;
        }
        x++;
    }
    for (int j=1;j<=n+1;j++)
    {
        h[n+2][j]=n+1;
    }
}



int main()
{
    init();
    int hmax=-1;
    int ans=0;
    for (int i=2;i<=n+1;i++)
        for (int j=1;j<=n+1;j++)
        {
            if (h[i+1][j]!=i)
                {
                    hmax=-1;
                    continue;
                }
            if (hmax==-1)
            {
                if ((i-h[i][j])==(d[i][j]-d[h[i][j]][j]))
                    hmax=i-h[i][j];
                if (hmax==(d[i][j+1]-d[h[i][j]][j+1]))
                {
                    ans++;
                }
                continue;   
            }
            else
            {
                if ((d[i][j]-d[h[i][j]][j])>0)
                    hmax=-1;
                if ((i-h[i][j])!=hmax)
                    hmax=-1;
                if (hmax==-1)
                    if ((i-h[i][j])==(d[i][j]-d[h[i][j]][j]))
                        hmax=i-h[i][j];
                if (hmax==(d[i][j+1]-d[h[i][j]][j+1]))
                {
                    ans++;
                    continue;
                }
            }
        }
    printf("%d",ans);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值