POJ 3690 0与* 二维哈希 模板 +multiset

Constellations

Time Limit: 3000MS   Memory Limit: 65536K
Total Submissions: 5923   Accepted: 1164

Description

The starry sky in the summer night is one of the most beautiful things on this planet. People imagine that some groups of stars in the sky form so-called constellations. Formally a constellation is a group of stars that are connected together to form a figure or picture. Some well-known constellations contain striking and familiar patterns of bright stars. Examples are Orion (containing a figure of a hunter), Leo (containing bright stars outlining the form of a lion), Scorpius (a scorpion), and Crux (a cross).

In this problem, you are to find occurrences of given constellations in a starry sky. For the sake of simplicity, the starry sky is given as a N× M matrix, each cell of which is a ‘*‘ or ‘0‘ indicating a star in the corresponding position or no star, respectively. Several constellations are given as a group of T P × Q matrices. You are to report how many constellations appear in the starry sky.

Note that a constellation appears in the sky if and only the corresponding P × Q matrix exactly matches some P × Q sub-matrix in the N ×M matrix.

Input

The input consists of multiple test cases. Each test case starts with a line containing five integers N, M, T, P and Q(1 ≤ N, M ≤ 1000, 1 ≤ T≤ 100, 1 ≤ P, Q ≤ 50). 
The following N lines describe the N × M matrix, each of which contains M characters ‘*‘ or ‘0‘.
The last part of the test case describe T constellations, each of which takes P lines in the same format as the matrix describing the sky. There is a blank line preceding each constellation.
The last test case is followed by a line containing five zeros.

Output

For each test case, print a line containing the test case number( beginning with 1) followed by the number of constellations appearing in the sky.

Sample Input

3 3 2 2 2
*00
0**
*00

**
00

*0
**
3 3 2 2 2
*00
0**
*00

**
00

*0
0*
0 0 0 0 0

Sample Output

Case 1: 1
Case 2: 2

Source

2008 Asia Hefei Regional Contest Online by USTC

题意:给定一个n*m矩阵和t个p*q的矩阵,求这t个矩阵有多少个是n*m的子矩阵。

矩阵都是01矩阵,只有‘0‘ ‘*‘

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <algorithm>
#include <set>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define MM(a,b) memset(a,b,sizeof(a));
const double eps = 1e-10;
const int  inf =0x7f7f7f7f;
const double pi=acos(-1);
const int maxn=5+1000;

int ans=inf;
int n,m,t,p,q,cas=0;
char text[maxn][maxn];
ull b1[1004],b2[1004];
char pat[55][55];
ull htmp[1005][1005],h[1005][1005];

ull base1=1e7+7;
ull base2=1e8+7;

void init()
{
    b1[0]=1;b2[0]=1;
    for(int i=1;i<1003;i++) b1[i]=b1[i-1]*base1;
    for(int i=1;i<1003;i++) b2[i]=b2[i-1]*base2;

}

ull calhash1()
{
    ull res=0;
    for(int i=0;i<p;i++)
    {
        ull k=0;
        for(int j=0;j<q;j++)
           k=k*base1+pat[i][j];
        res=res*base2+k;
    }
    return res;
}

void calhash2()
{
   for(int i=0;i<n;i++)
   {
       for(int j=0;j<q;j++) htmp[i][j]=j==0?text[i][j]:htmp[i][j-1]*base1+text[i][j];
       for(int j=q;j<m;j++) htmp[i][j]=htmp[i][j-1]*base1+text[i][j]-text[i][j-q]*b1[q];
   }
   for(int j=0;j<m;j++)
   {
       for(int i=0;i<p;i++) h[i][j]=i==0?htmp[i][j]:h[i-1][j]*base2+htmp[i][j];
       for(int i=p;i<n;i++) h[i][j]=h[i-1][j]*base2+htmp[i][j]-htmp[i-p][j]*b2[p];//求前缀
   }
}

multiset<ull> st;
int main()
{
    init();
    int cas=0;
    while(~scanf("%d%d%d%d%d",&n,&m,&t,&p,&q)&&(n+m+t+p+q))
    {
        st.clear();
        for(int i=0;i<n;i++)
            scanf("%s",text[i]);
        for(int k=0;k<t;k++)
            {
                for(int i=0;i<p;i++)
                    scanf("%s",pat[i]);
                st.insert(calhash1());
            }
        calhash2();
        int ans=0;
        for(int i=p-1;i<n;i++)
           for(int j=q-1;j<m;j++)
                   st.erase(h[i][j]);

        printf("Case %d: %d\n",++cas,t-st.size());
    }
    return 0;
}

错误点:

for(int i=p;i<n;i++) h[i][j]=h[i-1][j]*base2+htmp[i][j]-htmp[i-p][j]*b2[p]

刚开始写成了htmp[i][j]=htmp[i-1][j]*base2+htmp[i][j]-htmp[i-p][j]*b2[p]

其实这样是不对的,因为这样的话htmp是代表的前缀,所以一个数会减去多次,,所以需要建立一个新的h数组

wa代码:

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <stack>
#include <map>
#include <algorithm>
#include <set>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
#define MM(a,b) memset(a,b,sizeof(a));
const double eps = 1e-10;
const int  inf =0x7f7f7f7f;
const double pi=acos(-1);
const int maxn=5+1000;

int ans=inf;
int dx[6]={-1,0,1,0};
int dy[6]={0,1,0,-1};
int n,m,t,p,q,cas=0;
char text[maxn][maxn];
ull b1[1004],b2[1004];
char pat[1005][1005];
ull has[1005][1005];
ull base1=131;
ull base2=499;

void init()
{
    b1[0]=1;b2[0]=1;
    for(int i=1;i<1003;i++) b1[i]=b1[i-1]*base1;
    for(int i=1;i<1003;i++) b2[i]=b2[i-1]*base2;

}
ull H[1005][1005];

ull calhash1()
{
    ull res=0;
    for(int i=0;i<p;i++)
    {
        ull k=0;
        for(int j=0;j<q;j++)
           k=k*base1+pat[i][j];
        res=res*base2+k;
    }
    return res;
}

void calhash2()
{
   for(int i=0;i<n;i++)
   {
       for(int j=0;j<q;j++) has[i][j]=j==0?text[i][j]:has[i][j-1]*base1+text[i][j];
       for(int j=q;j<m;j++) has[i][j]=has[i][j-1]*base1+text[i][j]-text[i][j-q]*b1[q];
   }
   for(int j=0;j<m;j++)
   {
       for(int i=0;i<p;i++) has[i][j]=i==0?has[i][j]:has[i-1][j]*base2+has[i][j];
       for(int i=p;i<n;i++) has[i][j]=has[i-1][j]*base2+has[i][j]-has[i-p][j]*b2[p];
   }
}

set<ull> st;
int main()
{
    init();
    int cas=0;
    while(~scanf("%d%d%d%d%d",&n,&m,&t,&p,&q)&&(n+m+t+p+q))
    {
        st.clear();
        for(int i=0;i<n;i++)
            scanf("%s",text[i]);
        for(int k=0;k<t;k++)
            {
                for(int i=0;i<p;i++)
                    scanf("%s",pat[i]);
                st.insert(calhash1());
            }
        calhash2();
        int ans=0;
        for(int i=0;i<n;i++)
           for(int j=0;j<m;j++)
                   if(st.count(has[i][j])) st.erase(has[i][j]);

        printf("Case %d: %d\n",++cas,t-st.size());
    }
    return 0;
}
时间: 2024-08-10 18:52:04

POJ 3690 0与* 二维哈希 模板 +multiset的相关文章

POJ 1984 Navigation Nightmare 二维带权并查集

题目来源:POJ 1984 Navigation Nightmare 题意:给你一颗树 k次询问 求2点之间的曼哈顿距离 并且要在只有开始k条边的情况下 思路:按照方向 我是以左上角为根 左上角为原点 dx[i]为i点距离根的x坐标 dy[]是y坐标 这两个可以通过路径压缩求出 只不过是二维而已 #include <cstdio> #include <cstdlib> #include <cstring> using namespace std; const int m

POJ 2155 Matrix 【二维树状数组】

题目链接:http://poj.org/problem?id=2155 题目大意:给出一个N*N的0矩阵,下面给出两种指令:1. 给出的第一个数据为'C',再给出四个整形数据,x1,y1,y1,y2,对以(x1,y1)(x2,y2)分别为左上角和右下角坐标的矩阵内的元素进行反转(0变1,1变0)         2. 给出的第一个数据为'Q',再给出两个数据,x,y,然后输出此时这个坐标上的元素. 这题用二维树状数组解,树状数组能够对某区间更新所有元素的和,树状数组维护的是c[1][1]到c[i

hdu 4819 二维线段树模板

/* HDU 4819 Mosaic 题意:查询某个矩形内的最大最小值, 修改矩形内某点的值为该矩形(Mi+MA)/2; 二维线段树模板: 区间最值,单点更新. */ #include<bits/stdc++.h> using namespace std; const int INF = 0x3f3f3f3f; const int MAXN = 1010; int N, Q; struct Nodey { int l, r; int Max, Min; }; int locx[MAXN], l

【HDU 4819】Mosaic 二维线段树模板

二维线段树的模板题,和一维一样的思路,更新的时候注意一下细节. 存模板: /* 二维线段树模板整理 */ #include<cstdio> #include<algorithm> using namespace std; #define lson (pos<<1) #define rson (pos<<1|1) const int maxn = 805; const int INF = (1 << 30); int n; int posX[max

C#微信公众号接口开发,灵活利用网页授权、带参数二维码、模板消息,提升用户体验之完成用户绑定个人微信及验证码获取

一.前言 当下微信公众号几乎已经是每个公司必备的,但是大部分微信公众账号用户体验都欠佳,特别是涉及到用户绑定等,需要用户进行复杂的操作才可以和网站绑定,或者很多公司直接不绑定,而是每次都让用户填写账号密码.作为微信接口开发人员我们知道网页授权可以用作微信网页用作安全登录,带参数二维码的使用用作记录用户来源,模板消息用作购物消费等消息的通知,但是很少看到有综合利用这些高级接口做出体验比较好的公众账号,这里分享一些我开发的用户绑定和验证码的一些心得.所需要的接口有基础的回复.网页授权.带参数二维码.

POJ 1661 Help Jimmy(二维DP)

题目链接:http://poj.org/problem?id=1661 题目大意: 如图包括多个长度和高度各不相同的平台.地面是最低的平台,高度为零,长度无限. Jimmy老鼠在时刻0从高于所有平台的某处(高H处)开始下落,它的下落速度始终为1米/秒.当Jimmy落到某个平台上时,游戏者选择让它向左还是向右跑,它跑动的速度也是1米/秒.当Jimmy跑到平台的边缘时,开始继续下落.Jimmy每次下落的高度不能超过MAX米,不然就会摔死,游戏也会结束. 设计一个程序,计算Jimmy到底地面时可能的最

POJ 2155 Matrix【二维树状数组+YY(区间更新,单点查询)】

题目链接:http://poj.org/problem?id=2155 Matrix Time Limit: 3000MS   Memory Limit: 65536K Total Submissions: 32950   Accepted: 11943 Description Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th col

POJ 2155 Matrix【二维线段树】

题目大意:给你一个全是0的N*N矩阵,每次有两种操作:1将矩阵中一个子矩阵置反,2.查询某个点是0还是1 思路:裸的二维线段树 #include<iostream>#include<cstdio>#include <math.h>#include<algorithm>#include<string.h>#include<queue>#define MOD 1000003#define maxn 4009#define LL long

ZOJ 2859 二维RMQ(模板)

这题求范围最小值,RMQ正好是用来解决这方面的.所以再适合只是了,又是离线静态输入输出的,所以时间比二维线段树快. #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<map> #include<queue> #include<set> #include<cmath> #include<bit