2018.09.25【洛谷P4472】【BJWC2018】八维(字符串哈希)(倍增)

传送门


解析:

以后再也不把一个变量名当成另一个的子串了。。。
调了我好久。

思路:

显然这道题不哈希没法做。

然而串长有1e91e9直接做显然不行。

我们可以考虑倍增法,将所有长度为2kk2^{kk}字符串的哈希值都预处理。
然后倍增得到长度为KK的字符串。

由于八个方向之间的计算互不影响,所以我们分开算八次。


代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define cs const
#define re register 
#define gc getchar

inline
int getint(){
	re int num;
	re char c;
	while(!isdigit(c=gc()));
	num=c^48;
	while(isdigit(c=gc()))num=(num<<1)+(num<<3)+(c^48);
	return num;
}

inline
char getalpha(){
	re char c;
	while(!isalpha(c=gc()));
	return c;
}

inline
ull gcd(ull a,ull b){
	ull tmp;
	while(b){
		tmp=a-a/b*b;
		a=b;
		b=tmp;
	}
	return a;
} 

#define pow Pow
cs int N=501;
ull pow[30]={1000000007};
int n,m,K;
ull dp[30][N][N];
cs int dx[8]={1,1,1,0,0,-1,-1,-1};
cs int dy[8]={1,0,-1,1,-1,0,1,-1};
map<ull,int> ma;
char s[N][N];

signed main(){
	n=getint(),m=getint(),K=getint();
	for(int re i=0;i<n;++i)
	for(int re j=0;j<m;++j)
	dp[0][i][j]=getalpha()-'a';//得到初始数组
	for(int re kk=1;(1<<kk)<=K;++kk){
		pow[kk]=pow[kk-1]*pow[kk-1];
	}//倍增哈希的系数
	for(int re d=0;d<8;++d){//枚举方向
		for(int re kk=1;(1<<kk)<=K;++kk){//倍增
			for(int re i=0;i<n;++i)
			for(int re j=0;j<m;++j){
				dp[kk][i][j]=dp[kk-1][i][j]*pow[kk-1]
	+dp[kk-1][(i+dx[d]*(1<<(kk-1))%n+n)%n][(j+dy[d]*(1<<(kk-1))%m+m)%m];
			}
		}
		for(int re i=0;i<n;++i){
			for(int re j=0;j<m;++j){
				int x=i,y=j;
				ull now=0;
				int k=K;
				for(int re kk=29;~kk;--kk){
					if(k>=(1<<kk)){
						k-=1<<kk;
						now=now*pow[kk]+dp[kk][x][y];
						x=(x+dx[d]*(1<<kk)%n+n)%n;
						y=(y+dy[d]*(1<<kk)%m+m)%m;
					}
				}
				++ma[now];
			}
		}
	}
	ull a=0,b=64ll*n*n*m*m;//统计答案
	for(map<ull,int>::iterator it=ma.begin();it!=ma.end();++it){
		a=a+1ll*it->second*it->second;
	}
	ull g=gcd(a, b);
	cout<<a/g<<"/"<<b/g<<endl;
	return 0;
}
发布了968 篇原创文章 · 获赞 370 · 访问量 7万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 技术黑板 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览