ACM大一寒假集训week1.2

写在前面:

用printf输出一个浮点数用f而不用lf

洛谷P1659 [国家集训队]拉拉队排练:

求出奇数长度的回文串,加入以i为中心的回文串长度为5,那么它还包含长度为3的,长度为1的,可以求一个后缀和,用快速幂加速

难度:3

  1. 字符串哈希

①自然溢出(unsigned long long)

②单哈希(用大质数)

③双哈希

难度:2

  1. HDU 4622 Reincarnation

求区间不相同子串个数

用哈希的方法:

区间哈希求法:

for (int L = 1; L <= len; L++)
		{
			for (int i = 1; i + L - 1 <= len; i++)
			{
				a[i][i+L-1] = hah[i + L - 1] - hah[i - 1] * Pow[L];
			}
		}

把哈希值相同的挂一个链表上,存一下序列位置且能保证链表尾递增,具体看代码

#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iostream>
using namespace std;
#define re register int
#define ull unsigned long long
#define ll long long
#define INF 0x3f3f3f3f
#define N 3009
#define lson rt << 1
#define rson rt << 1 | 1
#define ne e[i].to
#define mo 998244353
#define lowbit(x) (x) & (-(x))
inline ll read()
{
	ll 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 << 1) + (x << 3) + (ll)(ch - '0');
		ch = getchar();
	}
	return x * f;
}
ull Pow[N], hah[N];
int head[10010], cnt, T, ans[2020][2020];
char st[2020];
struct node
{
	ull nex, val, id, pre;
} e[N];
int insert(ull val, int id)
{
	int u = val % 10007;
	for (int i = head[u]; i; i = e[i].nex)
	{
		if (val == e[i].val)
		{
			int tmp = e[i].pre;
			e[i].pre = id;
			return tmp;
		}
	}
	e[++cnt].nex = head[u];
	head[u] = cnt;
	e[cnt].pre = id;
	e[cnt].val = val;
	return 0;
}
int main()
{
	Pow[0] = 1;
	for (int i = 1; i <= 3000; i++)
		Pow[i] = Pow[i - 1] * 131;
	int T = read();
	while (T--)
	{
		scanf("%s", st);
		int len = strlen(st);
		for (int i = 1; i <= len; i++)
			hah[i] = hah[i - 1] * 131 + st[i - 1] - 'a';
		memset(ans, 0, sizeof(ans));
		for (int L = 1; L <= len; L++)
		{
			memset(head, 0, sizeof(head));
			cnt = 0;
			for (int i = 1; i + L - 1 <= len; i++)
			{
				int tmp = insert(hah[i + L - 1] - hah[i - 1] * Pow[L], i);
				ans[i][i + L - 1]++;
				ans[tmp][i + L - 1]--;
			}
		}
		for (int i = len; i >= 0; i--)
			for (int j = i; j <= len; j++)
				ans[i][j] += ans[i + 1][j] + ans[i][j - 1] - ans[i + 1][j - 1];
		int Q = read();
		while (Q--)
		{
			int l = read(), r = read();
			printf("%d
", ans[l][r]);
		}
	}
	return 0;
}

难度:3

  1. P4503 [CTSC2014]企鹅QQ

①.预处理,算出前i段的哈希值(这里使用的为进制哈希)
②.枚举不同位是哪一位,
求所有字符串在去掉这一位后的哈希值,
用排序等方法统计相同的对数。

设去掉的是第k位置的哈希值:

x = hs[i - 1] * p[len - i] + hs[len] - hs[i] * p[len - i]

难度:3

  1. HDU2896

AC自动机,只要用堆或者其他什么的东西记录一下匹配到的编号,然后排序就行,建议用stl库里的堆处理

难度:3

  1. KMP模板

KMP都看了好久QAQ,太菜了

#include<bits/stdc++.h>
#define ll long long
#define inf 0x7fffff
#define N 1000010
#define lson rt<<1
#define rson rt<<1|1
#define mo 998244353
using namespace std;
ll read()
{
	ll x=0;int 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 nex[N],lena,lenb;
char s1[N],s2[N];
void getnex()
{
	int j=0;
	for (int i=1;i<lenb;i++)
	{
		while (j&&s2[i]!=s2[j]) j=nex[j];
		j+=s2[i]==s2[j]?1:0;
		nex[i+1]=j;
	}
}
int main()
{
	scanf("%s%s",s1,s2);
	lena=strlen(s1),lenb=strlen(s2);
	getnex();
	int j=0;
	for (int i=0;i<lena;i++)
	{
		while (j&&s1[i]!=s2[j]) j=nex[j];
		j+=s1[i]==s2[j]?1:0;
		if (j==lenb) printf("%d
",i-lenb+2);
	}
	for (int i=1;i<=lenb;i++) printf("%d ",nex[i]);
	return 0;
}

难度:2

原文地址:https://www.cnblogs.com/71-111/p/14343935.html