1. 程式人生 > >[BZOJ2462]矩陣模板(暴力||矩陣hash)

[BZOJ2462]矩陣模板(暴力||矩陣hash)

題目描述

傳送門

題解

樸素的暴力就能A掉,資料弱。
學習了一下矩陣hash。
感覺非常玄學;剛開始把每一行轉化成2進位制數,然後把所有的行合併起來轉化成2b進位制數,就得到了一個矩陣的hash值。
算出來所有小矩陣的hash值,然後把大矩陣裡的每一個小矩陣的hash值也算出來,查詢就行了。
很玄學的是%的數,貌似讓它直接炸掉就可以了= =兩次模的是一樣的數?
TA說概率很科學。

程式碼

暴力

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace
std; int n,m,a,b,q; int A[1005][1005],B[1005][1005]; bool flag; char s[1005]; int main(){ scanf("%d%d%d%d\n",&n,&m,&a,&b); for (int i=1;i<=n;++i){ gets(s); for (int j=1;j<=m;++j) A[i][j]=s[j-1]-'0'; } scanf("%d\n",&q); while (q--){ for
(int i=1;i<=a;++i){ gets(s); for (int j=1;j<=b;++j) B[i][j]=s[j-1]-'0'; } for (int i=1;i<=n-a+1;++i) for (int j=1;j<=m-b+1;++j){ flag=true; for (int k=1;k<=a;++k) for (int l=1;l<=b;++l) if
(A[i+k-1][j+l-1]!=B[k][l]){ flag=false; k=a+1; l=b+1; } if (flag) { i=n+1; j=m+1; } } if (flag) printf("1\n"); else printf("0\n"); } }

hash

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
using namespace std;
#define ll unsigned long long

const int max_n=1e3+5;

int n,m,a,b,q;
char s[max_n];
int A[max_n][max_n],B[max_n][max_n];

ll S;
ll mt[max_n][max_n],squ[max_n];
ll mi2[max_n],miS[max_n];
ll hash[max_n*max_n],temp;

int main(){
    scanf("%d%d%d%d\n",&n,&m,&a,&b);

    S=1<<b;
    int N=max(a,b);
    mi2[0]=1;
    for (int i=1;i<=N;++i)
      mi2[i]=mi2[i-1]*2;

    miS[0]=1;
    for (int i=1;i<=N;++i)
      miS[i]=miS[i-1]*S;



    for (int i=1;i<=n;++i){
        gets(s);
        for (int j=1;j<=m;++j)
          A[i][j]=s[j-1]-'0';
    }

    for (int i=1;i<=n;++i){

        ll ans=0;
        for (int j=1;j<=b;++j)
          ans=ans+A[i][j]*mi2[b-j];
        mt[i][1]=ans;

        for (int j=2;j<=m-b+1;++j){
            ll head=A[i][j-1];
            ll tail=A[i][j+b-1];
            ans=ans*2-head*mi2[b]+tail;
            mt[i][j]=ans;
        }
    }

    for (int i=1;i<=m-b+1;++i){

        ll ans=0;
        for (int j=1;j<=a;++j)
          ans+=mt[j][i]*miS[a-j];
        hash[++temp]=ans;

        for (int j=2;j<=n-a+1;++j){
            ll head=mt[j-1][i];
            ll tail=mt[j+a-1][i];
            ans=ans*S-head*miS[a]+tail;
            hash[++temp]=ans;
        }

    }

    temp=unique(hash+1,hash+temp+1)-hash-1;
    sort(hash+1,hash+temp+1);

    scanf("%d\n",&q);

    while (q--){

        if (n<a||m<b){
            puts("0");
            continue;
        }


        for (int i=1;i<=a;++i){
            gets(s);
            for (int j=1;j<=b;++j)
              B[i][j]=s[j-1]-'0';
        }

        for (int i=1;i<=a;++i){
            ll ans=0;
            for (int j=1;j<=b;++j)
              ans=ans+B[i][j]*mi2[b-j];
            squ[i]=ans;
        }


        ll ans=0;
        for (int i=1;i<=a;++i)
          ans+=squ[i]*miS[a-i];
        if (hash[ lower_bound(hash+1,hash+temp+1,ans)-hash ]==ans) puts("1");
        else puts("0");
    }
}

總結

%的數還是要搞懂一下。