首页 > 其他分享 >[COCI2016-2017#4] Osmosmjerka 题解

[COCI2016-2017#4] Osmosmjerka 题解

时间:2023-09-23 16:46:24浏览次数:38  
标签:cnt vc int 题解 long 哈希 COCI2016 字符串 2017

[COCI2016-2017#4] Osmosmjerka 题解

我们发现对于每个点,只有八个方向,也就是说,最终能得到的字符串只会有 \(8nm\) 个,那我们可以考虑把这些字符串的哈希值求出来,相同的哈希值代表选到相同字符串的一种可能,直接统计即可。

现在的问题就在于,怎么快速地求出这 \(8nm\) 个字符串的哈希值。因为 \(k\) 很大,所以我们不能暴力求。发现我们只关心最后长度为 \(k\) 的字符串的哈希值,所以我们可以考虑用倍增优化求哈希。令 \(Hash_{i, j, k}\) 为在点 \((i, j)\) 处向一个方向延伸 \(2^k\) 个字符后得到的字符串的哈希值,这样,把长度按二进制拆开后,逐个加上为 \(1\) 的位上保存的哈希值就可以了(当然必须要乘上增加的底数)。

我们对每个延伸方向都这么做一遍就可以了。

需要注意的是,如果哈希的时候取模,可能会很慢。这里用的是自然溢出,当然评测机心情不好的时候还是要开 O2 才过(

代码:

#include <iostream>
#include <algorithm>
#include <vector>
#include <ctime>
#define ULL unsigned long long
using namespace std;
const int N = 505;
const int pa = 13331;
const int mod = 998244853;
long long gcd(long long a, long long b) {
	return b == 0 ? a : gcd(b, a % b);
}
char mp[N][N];
ULL pwa[34];
ULL hasha[N][N][34];
int n, m, K;
int dx[8] = {0, 0, 1, -1, 1, -1, 1, -1};
int dy[8] = {1, -1, 0, 0, 1, 1, -1, -1};

ULL vc[2000010];
int top;
int pw2[33];
void solve() {
	pw2[0] = 1;
	for(int i = 1; i<=30; ++i) {
		pw2[i] = pw2[i-1]<<1;
	}
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= m; ++j) {
			hasha[i][j][0] = (mp[i][j] - 'a' + 1);
		}
	}
	for (int d = 0; d < 8; ++d) {
		
		int tx, ty;
		for (int k = 1; k <= 29; ++k) {
			for (int i = 1; i <= n; ++i) {
				for (int j = 1; j <= m; ++j) {

					tx = (i + pw2[k-1] * dx[d] - 1) % n;
					ty = (j + pw2[k-1] * dy[d] - 1) % m;
					tx = (tx + n) % n + 1;
					ty = (ty + m) % m + 1;//求出延伸后的点的坐标
					hasha[i][j][k] = (hasha[i][j][k - 1] * pwa[k - 1] + hasha[tx][ty][k - 1]);
				}
			}
		}
		for (int i = 1; i <= n; ++i) {
			for (int j = 1; j <= m; ++j) {

				int nowx = i, nowy = j;
				ULL tmp = 0;
				for (int k = 0; k <= 29; ++k) {
					if ((K >> k) & 1) {
						tmp = tmp * pwa[k] + hasha[nowx][nowy][k];
						nowx = (nowx + pw2[k] * dx[d] - 1) % n;
						nowy = (nowy + pw2[k] * dy[d] - 1) % m;
						nowx = (nowx + n) % n + 1;
						nowy = (nowy + m) % m + 1;
					}
				}
				vc[++top] = tmp;
			}
		}
	}
	sort(vc+1, vc+top+1);
	long long U = 0;
	long long cnt = 0;
	for (int i = 1; i <= top; ++i) {
		if (i > 0 && vc[i] != vc[i - 1]) {
			U += (cnt * cnt);//两个人选出这个字符串都有 cnt 种方案,故共 cnt * cnt 种方案
			cnt = 1;
		} else {
			++cnt;
		}
	}
	U += (cnt * cnt);
	long long D = (1ll * top * top);//总方案数
	long long g = gcd(U, D);
	
	printf("%lld/%lld\n", U / g, D / g);
}
int main() {
	pwa[0] = pa;
	for (int i = 1; i <= 32; ++i) {
		pwa[i] = pwa[i - 1] * pwa[i - 1];
	}
	scanf("%d%d%d", &n, &m, &K);
	for (int i = 1; i <= n; ++i) {
		scanf("%s", mp[i] + 1);
	}
	solve();
	return 0;
}

标签:cnt,vc,int,题解,long,哈希,COCI2016,字符串,2017
From: https://www.cnblogs.com/frostwood/p/17724628.html

相关文章

  • 题解 CF1257G【Divisor Set】
    problem我们说一个集合\(D\)是一个好的集合,当不存在集合中的两个不同元素\(a,b\)使得\(a\)是\(b\)的约数。给定一个超大整数的素数表示形式\(N=\prod_{i=1}^n{p_i}\),要求从它的所有因子中选择尽可能多的元素组成一个好的集合。问这个最大的size是多少,输出模99824......
  • 题解 ARC165F【Make Adjacent】
    区间排序问题,主席树优化建图,最小字典序拓扑排序(priority_queue)problem给定一个长度为\(n*2\)的序列,其中每种元素恰好出现了2次。允许每次选择任意两个相邻的元素交换。那么必定存在一个最小\(k\):使得\(k\)次交换以后所有相同的元素都是相邻的。问恰好操作\(k\)次后,......
  • 【POJ 1521】Entropy 题解(贪心算法+优先队列+哈夫曼树)
    熵编码器是一种数据编码方法,通过对删除了“浪费”或“额外”信息的消息进行编码来实现无损数据压缩。换句话说,熵编码去除了最初不需要的信息,以准确编码消息。高度的熵意味着一条消息包含大量浪费的信息;以ASCII编码的英文文本是具有极高熵的消息类型的示例。已经压缩的消息,如JPEG图......
  • 题解 CF1873H Mad City
    题意描述马塞尔和瓦勒里乌(Valeriu)所在的疯狂城市由\(n\)栋建筑和\(n\)条双向道路组成。马塞尔和瓦勒里乌(Valeriu)分别从\(a\)号和\(b\)号建筑开始。马塞尔想赶上瓦勒里乌(换句话说,与他在同一栋楼里或在同一条路上相遇)。在每次移动过程中,他们都会选择前往当前建筑的邻近建......
  • 'main' attribute cannot be used in a module that contains top-level code 问题解
    核心是@main注解在main.swift文件中,可以重新命名下参考资料https://stackoverflow.com/questions/73431031/swift-cli-app-main-attribute-cannot-be-used-in-a-module-that-contains-top-leve......
  • CF1842F Tenzing and Tree 题解
    TenzingandTree感觉很典型的题,就是树的重心+绝对值等式解法:以每个点\(i\)为根分别\(bfs\),得到一个距离数组\(dis\),取前\(k\)个值的权值为和,更新\(w[k]\)的值,\(n\)个点分别为根,更新\(n\)遍之后,得到\(w\)数组,则\((n-1)\timesi-w[i]\),即为\(i\)个点时候的......
  • 砝码称重 题解
    砝码称重题解前言这道题时限完全可以开到1s,空间也开不到1024kb白想那么多优化(不过这个复杂度可能是目前来看最合理(算出来保证能过)的。题意简述有一个长度为\(n\)的序列\(a\),有两种操作:把\(l\)到\(r\)的所有数改为\(x\);查询用\(l\)到\(r\)的所有数(每个数可......
  • 题解 AtCoder Beginner Contest 267 A~H
    ABC267solutionhttps://atcoder.jp/contests/abc267/ProblemA.Saturday题目描述输入一个表示星期的英文字符串,输出:还有多少天到星期六?solution依题意模拟。\(O(1)\)。ProblemB.Split?题目描述Robin有十个小球,如图排列成这样,然后Robin将一些球击飞了,他告诉你哪些......
  • Django跨域问题解决
    Django跨域问题解决今天在学习前端Vue框架的过程中,遇到了跨域相关问题问题1详情:AccesstoXMLHttpRequestat'http://127.0.0.1:8000/book/'fromorigin'http://localhost:63342'hasbeenblockedbyCORSpolicy:No'Access-Control-Allow-Origin'headerispre......
  • P5836 [USACO19DEC] Milk Visits S - 洛谷题解
     题目链接:[P5836] USACO19DEC] MilkVisitsS-洛谷|计算机科学教育新生态(luogu.com.cn)这道题可以用并查集来解决。题目中每个结点只有两个状态:H和G。那么我们可以推断出,只有当起点和终点间每个结点的状态相同但是起点(或者终点或起点到终点之间的某一点)与所需状态不同......