KMP算法
用于字符串匹配,时间复杂度为O(m+n)(主串和子串长度),模板如下:
//KMP算法
const int MAX = 1e6 + 5;
#define MaxSize MAX
typedef struct
{
char data[MaxSize];
int length; //串长
} SqString;
void GetNextval(SqString t, int nextval[])
//由模式串t求出nextval值
{
int j = 0, k = -1;
nextval[0] = -1;
while (j < t.length)
{
if (k == -1 || t.data[j] == t.data[k])
{
j++; k++;
if (t.data[j] != t.data[k])
nextval[j] = k;
else
nextval[j] = nextval[k];
}
else k = nextval[k];
}
}
int KMPIndex1(SqString s, SqString t)
{
int nextval[MaxSize], i = 0, j = 0;
GetNextval(t, nextval);
while (i < s.length && j < t.length)
{
if (j == -1 || s.data[i] == t.data[j])
{
i++; j++;
}
else j = nextval[j];
}
if (j >= t.length)
return(i - t.length);
else
return(-1);
}
P3375 【模板】KMP字符串匹配
板子题,子串可能多次出现,后面要求输出的值就是nextval数组中的值,代码如下:
#include <iostream>
#include<cstring>
using namespace std;
//P3375 【模板】KMP字符串匹配
string s1, s2;
int kmp[1000005]; //这里的kmp就是nextval
int main() {
ios::sync_with_stdio(false);
cin >> s1 >> s2;
int len1 = s1.length();
int len2 = s2.length();
int j = 0;
for (int i = 1; i < len2; i++) { //自己匹配自己
while (s2[i] != s2[j] && j)j = kmp[j];
kmp[i + 1] = (s2[i] == s2[j] ? ++j : 0);
}
j = 0;
for (int i = 0; i < len1; i++) {
while (j && s1[i] != s2[j])j = kmp[j];
j += (s1[i] == s2[j] ? 1 : 0);
if (j == len2)cout << i - len2 + 2 << '\n';
}
for (int i = 1; i <= len2; i++) {
cout << kmp[i] << ' ';
}
return 0;
}
P8630 [蓝桥杯 2015 国 B] 密文搜索
这道题我使用了map数组,先将输入的密码排序之后,存入map数组中,赋值为1,之后则一段一段8个字符的截取给出的资料,并排序,设ans为答案,则每次都让ans加上截取的字符串在map数组中的值。代码如下:
#include <iostream>
#include<cstring>
using namespace std;
//P8630 [蓝桥杯 2015 国 B] 密文搜索v
#include<map>
#include<algorithm>
map<string, int>a;
int main() {
ios::sync_with_stdio(false);
string s, ss;
int n;
cin >> s >> n;
for (int i = 0; i < n; i++) {
cin >> ss;
sort(ss.begin(), ss.end());
a[ss]++;
}
int ans = 0;
for (int i = 0; i < s.size() - 7; i++) {
ss = s.substr(i,8);
sort(ss.begin(), ss.end());
ans += a[ss];
}
cout << ans;
return 0;
}
cf: Hossam and Trainees
我们首先需要筛出数据范围内的所有素数,用map数组存储每一个素数出现的次数,然后判断每一个质数因子出现次数,若出现了两次,就直接输出YES。
#include<iostream>
#include<cstring>
#include<map>
#include<vector>
#include<algorithm>
using namespace std;
const int MAXN = 1e5 + 5;
bool isnp[MAXN];
vector<int> primes; // 质数表
void init(int n) {
for (int i = 2; i <= n; i++) {
if (!isnp[i])
primes.push_back(i);
for (int p : primes) { //遍历质数表
if (p * i > n)
break;
isnp[p * i] = 1;
if (i % p == 0)
break;
}
}
}
int a[MAXN];
void solve() {
int n;
cin >> n;
map<int, int>mp;
for (int i = 1; i <= n; i++)cin >> a[i];
for (int i = 1; i <= n; i++) {
int num = a[i];
for (int j = 0; primes[j] * primes[j] <= num; j++) {
int p = primes[j];
if (num % p == 0) {
while (num % p == 0)num /= p;
mp[p]++;
if (mp[p] > 1) {
cout << "YES\n";
return;
}
}
}
if (num > 1) {
mp[num]++;
}
if (mp[num] > 1) {
cout << "YES\n";
return;
}
}
cout << "NO\n";
}
int main() {
ios::sync_with_stdio(false);
int t;
cin >> t;
init(MAXN);
while (t--) {
solve();
}
return 0;
}
P3366 【模板】最小生成树
优先添加边长小的两个顶点,使用并查集判断添加后是否会成环,用num记录添加边的条数,sum累计边长之和,若等于(顶点个数)n-1,则说明连通,输出sum,否则输出orz。
#include <iostream>
#include<cstring>
using namespace std;
//P3366 【模板】最小生成树
#include<algorithm>
typedef struct {
int x, y, l;
}egde;
const int MAX = 2e5 + 5;
egde e[MAX];
int pre[5005];
bool cmp(egde a, egde b) {
return a.l < b.l;
}
int find(int f) {
if (pre[f] == f || pre[f] == 0)return pre[f] = f;
else return pre[f] = find(pre[f]);
}
int main() {
ios::sync_with_stdio(false);
int n, m;
cin >> n >> m;
for (int i = 0; i < m; i++) {
cin >> e[i].x >> e[i].y >> e[i].l;
}
sort(e, e + m, cmp);
int num = 0, sum = 0;
for (int i = 0; i < m; i++) {
int f1 = find(e[i].x);
int f2 = find(e[i].y);
if (f1 != f2) {
pre[f2] = f1;
num++;
sum += e[i].l;
}
}
if (num == n - 1) {
cout << sum;
}
else cout << "orz";
return 0;
}
这两天学习目标有些不明确,遇到难点有点懈怠,导致学习效率有点低,在做题时,光想着简便的方法,却忽略了问题的本质,这是不应该的。
明天加油!