BZOJ-2462&&2351 矩阵模板&&Matrix 暴力 or Hash orAC自动机 or KMP

3 篇文章 0 订阅
2 篇文章 0 订阅

2462: [BeiJing2011]矩阵模板
Time Limit: 2 Sec Memory Limit: 128 MB
Submit: 717 Solved: 316
[Submit][Status][Discuss]

Description
给定一个M行N列的01矩阵,以及Q个A行B列的01矩阵,你需要求出这Q个矩阵哪些在
原矩阵中出现过。
所谓01矩阵,就是矩阵中所有元素不是0就是1。

Input
输入文件的第一行为M、N、A、B,参见题目描述。
接下来M行,每行N个字符,非0即1,描述原矩阵。
接下来一行为你要处理的询问数Q。
接下来Q个矩阵,一共Q*A行,每行B个字符,描述Q个01矩阵。

Output
你需要输出Q行,每行为0或者1,表示这个矩阵是否出现过,0表示没有出现过,1表示出现过。

Sample Input
3 3 2 2
111
000
111
3
11
00
11
11
00
11

Sample Output
1
0
1

HINT
对于100%的数据,A < = 100。

Source
Day4

.

2351: [BeiJing2011]Matrix
Time Limit: 20 Sec Memory Limit: 128 MB
Submit: 740 Solved: 212
[Submit][Status][Discuss]

Description
给定一个M行N列的01矩阵,以及Q个A行B列的01矩阵,你需要求出这Q个矩阵哪些在原矩阵中出现过。
所谓01矩阵,就是矩阵中所有元素不是0就是1。

Input
输入文件的第一行为M、N、A、B,参见题目描述。
接下来M行,每行N个字符,非0即1,描述原矩阵。
接下来一行为你要处理的询问数Q。
接下来Q个矩阵,一共Q*A行,每行B个字符,描述Q个01矩阵。

Output
你需要输出Q行,每行为0或者1,表示这个矩阵是否出现过,0表示没有出现过,1表示出现过。

Sample Input
3 3 2 2
111
000
111
3
11
00
11
11
00
11

Sample Output
1
0
1

HINT
对于100%的实际测试数据,M、N ≤ 1000,Q = 1000
对于40%的数据,A = 1。
对于80%的数据,A ≤ 10。
对于100%的数据,A ≤ 100。

Source

题解
2351是2462的数据强化版,对于2462,可以直接暴力;
自己的写法是,记录了一下矩形的0的数目,用二维树状数组的思路,求出子矩阵的0的数目,询问时先比较数目再一一比对;
2462就必须换方法了,这里用的是hash,在做的时候,考虑到了hash,但YY出问题了,大体的思路是:
把每行展成字符串,总之,读入大的矩阵,把大矩阵的每个子矩阵hash,(每个子矩阵的hash值和暴力优化的那个思想很类似),这样每次读入小矩阵可以直接同样的方法hash,与大矩阵的子矩阵比较即可。至于hash的重合概率,TA学长粗略计算是10^-3级的,所以几乎可以无视
同时可以用KMP或者AC自动机的方法,大体就是把一个矩阵的一行或者一列当作一个字符,来实现字符的匹配,自己并不是很会。

code1:(自己的暴力P2462)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
int read()
{
    int x=0,f=1; char ch=getchar();
    while (ch<'0' || ch>'9') {if (ch=='-') f=-1; ch=getchar();}
    while (ch>='0' && ch<='9') {x=x*10+ch-'0'; ch=getchar();}
    return x*f;
}
int n,m,a,b,q;
struct matr
{
    int a[1010][1010]; int nn,mm; int num0[1010][1010];
    matr(){memset(a,0,sizeof(a));memset(num0,0,sizeof(num0));}
};
struct matri
{
    int a[110][110]; int nn,mm; int num0[110][110];
    matri(){memset(a,0,sizeof(a));memset(num0,0,sizeof(num0));}
};
matri Mat[1010]; matr Ma;

bool pd(int x,int y,int lx,int ly,int now)
{
    bool f=1;
    for (int i=x-lx+1; i<=x; i++)
        for (int j=y-ly+1; j<=y; j++)
            if (Ma.a[i][j]!=Mat[now].a[(i-x+lx)][(j-y+ly)]) {f=0;break;}
    return f;
}
void solve(int now)
{
    bool f=0; int aa=Mat[now].nn,bb=Mat[now].mm;int nn0=Mat[now].num0[aa][bb];
    //printf("aa=%d bb=%d\n",aa,bb);
    for (int i=aa; i<=n; i++)
        for (int j=bb; j<=m; j++)
            {
                int n0=Ma.num0[i][j]-Ma.num0[i-aa][j]-Ma.num0[i][j-bb]+Ma.num0[i-aa][j-bb];
                if (n0==nn0) f=pd(i,j,aa,bb,now);
                //printf("NOW=%d i=%d j=%d    n0=%d nn0=%d F=%d\n",now,i,j,n0,nn0,f);
                if (f==1) {puts("1");return;}
            }
    puts("0");
}
int main()
{
    n=read();m=read(); a=read();b=read();
    Ma.nn=n; Ma.mm=m;
    for (int i=1; i<=n; i++)
        {
            char aaa[1010]; scanf("%s",aaa);
            for (int j=1; j<=m; j++)
                Ma.a[i][j]=aaa[j-1]-'0';
        }
    for (int i=1; i<=n; i++)
        for (int j=1; j<=m; j++)
            if (!Ma.a[i][j]) 
                Ma.num0[i][j]=Ma.num0[i-1][j]+Ma.num0[i][j-1]-Ma.num0[i-1][j-1]+1;
            else Ma.num0[i][j]=Ma.num0[i-1][j]+Ma.num0[i][j-1]-Ma.num0[i-1][j-1];
    q=read();
    for (int i=1; i<=q; i++)
        {
            Mat[i].nn=a; Mat[i].mm=b;
            for (int j=1; j<=a; j++)
                {
                    char aaa[1010]; scanf("%s",aaa);
                    for (int k=1; k<=b; k++)
                        {
                            Mat[i].a[j][k]=aaa[k-1]-'0';
                            if (!Mat[i].a[j][k]) 
                                Mat[i].num0[j][k]=Mat[i].num0[j-1][k]+Mat[i].num0[j][k-1]-Mat[i].num0[j-1][k-1]+1;
                            else Mat[i].num0[j][k]=Mat[i].num0[j-1][k]+Mat[i].num0[j][k-1]-Mat[i].num0[j-1][k-1];
                        }
                }
        }
    for (int i=1; i<=q; i++)
        solve(i);
    return 0;
}

code2:(hash,P2351)by TA学长

#include<cstdio>
#include<iostream>
using namespace std;
#include<cstring>
#include<algorithm>
const int M=1000+5,N=1000+5,A=100+5,B=1000+5;
const int Mod=1e9+7;
int mat[N][M];
typedef long long LL;
int hash[2][N][M],data[N*M];
int main(){
//  freopen("matrix.in","r",stdin);
//  freopen("matrix.out","w",stdout);
    int m,n,a,b;
    scanf("%d%d%d%d",&n,&m,&a,&b);
    char c;
    for(int i=0;i<n;++i)
        for(int j=0;j<m;++j){
            c=getchar();
            while(c<'0'||c>'1')c=getchar();
            mat[i][j]=c-'0';
        }
    LL base[2]={1,1};
    for(int i=b;i--;)base[0]=(base[0]<<1)%Mod;
    for(int i=n;i--;){
        for(int j=1;j<=b;++j)hash[0][i][m-b]=((hash[0][i][m-b]<<1)+mat[i][m-j])%Mod;
        for(int j=m-b-1;j>=0;--j)hash[0][i][j]=((hash[0][i][j+1]<<1)%Mod-mat[i][j+b]*base[0]+mat[i][j])%Mod;
        //for(int j=m-b;j>=0;--j)printf("hash(0,%d,%d)=%d\n",i,j,hash[0][i][j]);
    }
    for(int i=a;i--;)base[1]=base[1]*base[0]%Mod;
    for(int j=m-b;j>=0;--j){
        for(int i=1;i<=a;++i)hash[1][n-a][j]=(hash[1][n-a][j]*base[0]+hash[0][n-i][j])%Mod;
        for(int i=n-a-1;i>=0;--i)hash[1][i][j]=(hash[1][i+1][j]*base[0]-hash[0][i+a][j]*base[1]+hash[0][i][j])%Mod;
    }
    int tot=0;
    for(int i=n-a;i>=0;--i)
        for(int j=m-b;j>=0;--j){
            data[tot++]=(hash[1][i][j]+Mod)%Mod;
            //printf("hash(1,%d,%d)=%d\n",i,j,data[tot-1]);
        }
    sort(data,data+tot);
    tot=unique(data,data+tot)-data;
    int q,tmp;
    scanf("%d",&q);
    while(q--){
        tmp=0;
        for(int i=0;i<a;++i)
            for(int j=0;j<b;++j){
                c=getchar();
                while(c<'0'||c>'1')c=getchar();
                mat[i][j]=c-'0';
            }
        for(int i=a;i--;)
            for(int j=b;j--;)
                tmp=((tmp<<1)+mat[i][j])%Mod;
        //printf("%d\n",tmp);
        if(data[lower_bound(data,data+tot,tmp)-data]==tmp)puts("1");
        else puts("0");
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值