CF. 几个向量(可轮转)的映射是否相同(想法题)

http://codeforces.com/problemset/gymProblem/100203/D

哈希。。。For example, (1, 2, 2, 3) ≡ (22, 3, 4, 22) ,可以轮转成(4, 22, 22, 3),前面的1对应4, 2对应22, 3对应3,所以存在一个映射。

通过观察发现两个向量里的相同数字距离是一致的。

#include <bits/stdc++.h>    
using namespace std;    
typedef long long ll;  
int x[205];   
unsigned long long y[105],w[10005][105];  
int main() {    
    y[0]=1;  
    for(int i=1;i<=100;++i){  
        y[i]=y[i-1]*23333;  //超大的一个值(已溢出ull)   
    }  
    int t;  
    scanf("%d",&t); //这种10^7左右的题用scanf   
    while(t--){  
        memset(w,0,sizeof(w));  
        int n,m,a;  
        scanf("%d %d", &n, &m);  
        for(int i=1;i<=n;++i){  
            map<int,int> r;  
            for(int j=1;j<=m;++j){  
                scanf("%d",&x[j]);  
                x[j+m]=x[j];  
            }  
            for(int j=1;j<=m;++j){  
                a=x[j];  
                r[a]=j;  
            }  
            for(int j=m+1;j<=2*m;++j){  
                a=x[j];  
                w[i][j-m]=(j-r[a])%m;  //为了使每个数字第一次出现的位置赋上距离差  
				r[a]=j;   
            }  
        }  
        map<int,int> r;  
        int s=0;  
        for(int i=1;i<=n;++i){  
            unsigned long long p=0;  
            for(int j=1;j<=m;++j)  
                p=p*23333+w[i][j];  
            if(r.count(p))  
                continue;  
            s++;  
            r[p]=1;  
            for(int j=1;j<m;++j){  
    //          p=p/23333+y[m-1]*(p%23333); 错(大概是因为值实在太大了不能用除法)   
                p=(p-y[m-1]*w[i][j])*23333+w[i][j];  
                r[p]=1;  
            }  
        }  
        printf("%d\n",s);  
    }   
    return 0;    
}


你可能感兴趣的:(CF. 几个向量(可轮转)的映射是否相同(想法题))