CT 1459 字符串算法

A 子串查找

 

哈希加密函数:hash[i]=hash[i−1]∗p+idx(s[i])(idx指的是待加密字符串,p是质数)

哈希加密函数(带取余):hash[i]=(hash[i−1])∗p+idx(s[i]) % mod(p和mod都是质数)

查询某段的哈希值:hash=hash[r]−hash[l−1]∗p^(r−l+1) (因为哈希加密时会多次乘p,要在区间左端点乘上相应“长度”大小的p幂次来平衡式子)。

本题是哈希模板题。

//#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include<queue>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#define lldin(a) scanf_s("%lld", &a)
#define println(a) printf("%lld\n", a)
#define reset(a, b) memset(a, b, sizeof(a))
#define debug cout<<"procedures above are available"<<endl;
using namespace std;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1000000007;
const int tool_const = 19991126;
const int tool_const2 = 33;
inline ll nextlong()
{
    ll tmp = 0, si = 1;
    char c;
    c = getchar();
    while (c > '9' || c < '0')
    {
        if (c == '-')
            si = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        tmp = tmp * 10 + c - '0';
        c = getchar();
    }
    return si * tmp;
}
/**Maintain your determination.Nobody knows the magnificent landscape
at his destination before the arrival with stumble.**/
/**Last Remote**/
char a[5000000], b[5000000];
ull hashes[5000000],password[5000000];
void init(ll n)
{
    hashes[1] = 37;
    for (int i = 2; i <= n+3; i++)
        hashes[i] = hashes[i - 1] * 37;
}
ull encry(ll len)
{
    ll ans = 0;
    for (int i = 1; i <= len; i++)
        ans = ans * 37 + (b[i]);
    return ans;
}
void encry2(ll len)
{
    for (int i = 1; i <= len; i++)
        password[i] = (password[i-1] * 37)+ a[i];
}
int DETERMINATION()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    cin >> (a+1) >> (b+1);
    ll len1 = strlen(a + 1);
    ll len2 = strlen(b + 1);
    init(max(len1, len2));
    ull encryed = encry(len2);
    encry2(len1);
    ll cnt = 0;
    //cout << encryed << endl;
    for (int i = len2; i <= len1; i++)
    {
        //cout << password[i] - password[i - len2] * hashes[len2] << endl;
        if (encryed ==(password[i] - password[i - len2]*hashes[len2]))//取值函数
            cnt++;
    }
    cout << cnt << endl;
    return 0;
}

 

 

本题需要你设计一个重复率较低的哈希函数,一般P和mod取大质数即可。

map模组亦可解决。

//#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include<queue>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#define lldin(a) scanf_s("%lld", &a)
#define println(a) printf("%lld\n", a)
#define reset(a, b) memset(a, b, sizeof(a))
#define debug cout<<"procedures above are available"<<endl;
using namespace std;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1000000007;
const int tool_const = 19991126;
const int tool_const2 = 33;
inline ll nextlong()
{
    ll tmp = 0, si = 1;
    char c;
    c = getchar();
    while (c > '9' || c < '0')
    {
        if (c == '-')
            si = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        tmp = tmp * 10 + c - '0';
        c = getchar();
    }
    return si * tmp;
}
/**Maintain your determination.Nobody knows the magnificent landscape
at his destination before the arrival with stumble.**/
/**Last Remote**/
set<ull>st;
ull encry(string tmp)
{
    ll ans = 0;
    for (int i = 0; i < tmp.size(); i++)
        ans = (ans * 37) + tmp[i];
    return ans;
}
int DETERMINATION()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    ll n;
    cin >> n;
    string cmd,name;
    for (int i = 1; i <= n; i++)
    {
        cin >> cmd;
        getline(cin,name);
        if (cmd == "add")
            st.insert(encry(name));
        else
        {
            if (st.find(encry(name)) != st.end())
                cout << "yes" << endl;
            else
                cout << "no" << endl;
        }
    }
    return 0;
}

C  power string

找到字符串的最小正周期即可,但是枚举周期会超时。这里使用了KMP算法中的NEXT数组作为辅助

//#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include<queue>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#define lldin(a) scanf_s("%lld", &a)
#define println(a) printf("%lld\n", a)
#define reset(a, b) memset(a, b, sizeof(a))
#define debug cout<<"procedures above are available"<<endl;
using namespace std;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1000000007;
const int tool_const = 19991126;
const int tool_const2 = 33;
inline ll nextlong()
{
    ll tmp = 0, si = 1;
    char c;
    c = getchar();
    while (c > '9' || c < '0')
    {
        if (c == '-')
            si = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        tmp = tmp * 10 + c - '0';
        c = getchar();
    }
    return si * tmp;
}
/**Maintain your determination.Nobody knows the magnificent landscape
at his destination before the arrival with stumble.**/
/**Last Remote**/
char tmp[5000000];
ll nxt[5000000];
void getnext()
{
    ll ph = 0,pt = -1;
    nxt[0] = -1;
    ll len = strlen(tmp);
    while (ph<len)
    {
        if (pt == -1 || tmp[ph] == tmp[pt])
            nxt[++ph] = ++pt;
        else
            pt = nxt[pt];
    }
}
int DETERMINATION()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    while (cin >> tmp)
    {
        if (tmp[0] == '.')
            break;
        reset(nxt, 0);
        getnext();
        ll total = strlen(tmp);
        ll len2 = total / (total - nxt[total]);//总长度除以最小正周期
        cout << len2 << endl;
    }
    return 0;
}

 

 K 

KMP和哈希都可做。

//#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include<queue>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#define lldin(a) scanf_s("%lld", &a)
#define println(a) printf("%lld\n", a)
#define reset(a, b) memset(a, b, sizeof(a))
#define debug cout<<"procedures above are available"<<endl;
using namespace std;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1000000007;
const int tool_const = 19991126;
const int tool_const2 = 33;
inline ll nextlong()
{
    ll tmp = 0, si = 1;
    char c;
    c = getchar();
    while (c > '9' || c < '0')
    {
        if (c == '-')
            si = -1;
        c = getchar();
    }
    while (c >= '0' && c <= '9')
    {
        tmp = tmp * 10 + c - '0';
        c = getchar();
    }
    return si * tmp;
}
/**Maintain your determination.Nobody knows the magnificent landscape
at his destination before the arrival with stumble.**/
/**Last Remote**/
string text,sub;
ll nexxt[500000];
void getnext()
{
    ll pt = 0, pt2 = -1;
    nexxt[0] = -1;
    while (pt < sub.size())
    {
        if (pt2 == -1 || sub[pt2] == sub[pt])
        {
            nexxt[++pt] = ++pt2;
        }
        else
            pt2 = nexxt[pt2];
    }
}
ll cnt = 0;
void kmp()
{
    getnext();
    ll pt1 = 0, pt2 = 0;
    while (pt1 < text.size())
    {
        //cout << pt1 << " " << pt2 << endl;
        if (pt2 == -1 || sub[pt2] == text[pt1])
            pt2++, pt1++;
        else
            pt2 = nexxt[pt2];
        if (pt2 == sub.size())
        {
            cnt++;
            pt2 = 0;
        }
    }
}
int DETERMINATION()
{
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    while (cin >> text)
    {
        if (text == "#")
            break;
        cin >> sub;
        reset(nexxt, 0);
        cnt = 0;
        kmp();
        cout << cnt << endl;
    }
    return 0;
}

X 玄武密码

AC自动机模板题,不过需要在母串查询时对所经节点打标记。

//#include<pch.h>
#include <iostream>
#include <cstdio>
#include <bits/stdc++.h>
#include<queue>
#include <map>
#include <algorithm>
#include <stack>
#include <iomanip>
#include <cstring>
#include <cmath>
#define DETERMINATION main
#define lldin(a) scanf_s("%lld", &a)
#define println(a) printf("%lld\n", a)
#define reset(a, b) memset(a, b, sizeof(a))
#define debug cout<<"procedures above are available"<<endl;
using namespace std;
const int INF = 0x3f3f3f3f;
const double PI = acos(-1);
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
const int mod = 1000000007;
const int tool_const = 19991126;
const int tool_const2 = 33;
inline ll nextlong()
{
	ll tmp = 0, si = 1;
	char c;
	c = getchar();
	while (c > '9' || c < '0')
	{
		if (c == '-')
			si = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9')
	{
		tmp = tmp * 10 + c - '0';
		c = getchar();
	}
	return si * tmp;
}
/**Maintain your determination.Nobody knows the magnificent landscape
at his destination before the arrival with stumble.**/
/**Last Remote**/
char text[10000089], tmp[170001][2500];
int trie[10000071][5], fail[10000071], length[10000071];
int bottom[10000071];
bool vis[10000071];
ll cnt = 0;
ll cal(char x)//由于只有四个字母,只需要做一个四叉字典树即可。
{
	if (x == 'E')
		return 1;
	else if (x == 'N')
		return 2;
	else if (x == 'S')
		return 3;
	else if (x == 'W')
		return 4;
}
void ins(ll index,char *tmp)
{
	ll rt = 0;
	vis[0] = 1;
	for (int i = 0; tmp[i]; i++)
	{
		ll t = cal(tmp[i]);
		if (trie[rt][t] == 0)
			trie[rt][t] = ++cnt;
		rt = trie[rt][t];
	}
}
void getfail()
{
	queue<ll>q;
	for (int i = 1; i <= 4; i++)
	{
		if (trie[0][i])
		{
			fail[trie[0][i]] = 0;
			q.push(trie[0][i]);
		}
	}
	while (!q.empty())
	{
		ll current = q.front();
		q.pop();
		for (int i = 1; i <= 4; i++)
		{
			if (trie[current][i])
			{
				fail[trie[current][i]] = trie[fail[current]][i];
				q.push(trie[current][i]);
			}
			else
				trie[current][i] = trie[fail[current]][i];
		}
	}
}
void mark(char *t)
{
	ll current = 0;
	for (int i = 0; t[i]; i++)
	{
		current = trie[current][cal(t[i])];
		for (int j = current; j != 0; j = fail[j])//对fail指针经过的节点打标记
		{
			if (vis[j])
				break;
			else
				vis[j] = 1;
		}
	}
}
ll query(char *st)
{
	ll current = 0, ans = 0;
	for (int i = 0; st[i]; i++)
	{
		ll t = cal(st[i]);
		current = trie[current][t];
		if (vis[current])//找标记即可
			ans ++;
	}
	return ans;
}
int DETERMINATION()
{
	ios::sync_with_stdio(false);
	cin.tie(0), cout.tie(0);
	ll n, m;
	cin >> n >> m;
	cin >> text;
	for (int i = 1; i <= m; i++)
	{
		cin >> tmp[i];
		length[i] = strlen(tmp[i]);
		ins(i,tmp[i]);
	}
	getfail();
	mark(text);
	for (int i = 1; i <= m; i++)
		cout << query(tmp[i]) << endl;
	return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值