51 NOD 1753 相似子串 字符串hash
阿新 • • 發佈:2017-09-07
sin 相反數 ++ 歸類 printf gray def std nfa
1735 相似子串
基準時間限制:5 秒 空間限制:131072 KB 分值: 80
兩個字符串相似定義為:
1.兩個字符串長度相等
2.兩個字符串對應位置上有且僅有至多一個位置所對應的字符不相同
給定一個字符串,每次詢問兩個子串在給定的規則下是否相似。給定的規則指每次給出一些等價關系,如‘a‘=’b‘,‘b‘=’c‘等,註意這裏的等價關系具有傳遞性,即若‘a‘=’b‘,‘b‘=’c‘,則‘a‘=’c‘。 Input
Output
若某一聯通塊所對應的hash值的總和在兩個串中不相等則兩個串在給定規則下不相等,否則相等。
考慮只有一個位置不同的情況,那麽必然是存在兩個聯通塊對應的hash在兩個串上不相等,且這兩個差值是base的某個冪次的兩個相反數,
那麽預處理一下base所有次冪並存下即可。
時間復雜度O((|S|+T)*26)
1.兩個字符串長度相等
2.兩個字符串對應位置上有且僅有至多一個位置所對應的字符不相同
給定一個字符串,每次詢問兩個子串在給定的規則下是否相似。給定的規則指每次給出一些等價關系,如‘a‘=’b‘,‘b‘=’c‘等,註意這裏的等價關系具有傳遞性,即若‘a‘=’b‘,‘b‘=’c‘,則‘a‘=’c‘。 Input
第一行一個字符串s(1<=|s|<=300000) 第二行一個整數T(1<=T<=300000) 對於每次詢問: 第一行5個整數k,l1,r1,l2,r2,表示有k個等價規則,詢問的是子串[l1,r1],[l2,r2](1<=k<=10,1<=l1<=r1<=|s|,1<=l2<=r2<=|s|) 接下來k行每行兩個連續的字符表示這兩個字符等價。 此題中所有的字符均為小寫字母。
T行,若相似則輸出“YES”否則輸出“NO”Input示例
abac 3 1 1 2 3 4 bc 1 1 2 3 4 ac 1 1 2 2 3 acOutput示例
YES YES NO題解: hash值是由一系列字符* base^i 組成的,這裏首先按照字母歸類(如“aba”,按“a”歸類即為“a”*( base^1+base^3 )) 如果只是判斷在給定規則下是否相等,那麽可以把歸類後26個字母對應的hash值按照並查集裏的等價關系進行累加,
#include <bits/stdc++.h> inline long long read(){long long 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*10+ch-‘0‘;ch=getchar();}return x*f;} using namespace std; typedef unsigned long long ULL; const int N = 4e5+10; const ULL mod = 10000019ULL; ULL sqr[N], tmp = 1, pre[N][27], fi[50], se[50]; map<ULL, int> mp; char s[N], ch[50]; int T, fa[50], vis[50], F[50]; int finds(int x) {return fa[x] == x? x:fa[x]=finds(fa[x]);} int main() { scanf("%s%d",s+1,&T); int n = strlen(s+1); sqr[0] = 1; for(int i = 1; i <= n; ++i) sqr[i] = sqr[i-1] * mod, mp[sqr[i]] = 1,mp[(-sqr[i])] = 1; for(int i = 1; i <= n; ++i) { tmp = tmp * mod; pre[i][s[i] - ‘a‘ + 1] += tmp; } for(int i = 1; i <= n; ++i) { for(int j = 1; j <= 26; ++j) pre[i][j] += pre[i-1][j]; } for(int t = 1; t <= T; t++) { int k,l1,r1,l2,r2,cnt = 0; scanf("%d%d%d%d%d",&k,&l1,&r1,&l2,&r2); for(int i = 1; i <= 26; ++i) fa[i] = i,vis[i] = 0; for(int i = 1; i <= 26; ++i) fi[i] = pre[r1][i] - pre[l1-1][i]; for(int i = 1; i <= 26; ++i) se[i] = pre[r2][i] - pre[l2-1][i]; for(int i = 1; i <= k; ++i) { scanf("%s",ch); int fx = finds(ch[0] - ‘a‘ + 1); int fy = finds(ch[1] - ‘a‘ + 1); if(fx > fy) swap(fx,fy); if(fx != fy) fa[fy] = fx,fi[fx] += fi[fy],se[fx] += se[fy],fi[fy] = 0,se[fy] = 0; } if(r1 - l1 != r2 - l2) { printf("NO\n"); continue; } for(int i = 1; i <= 26; ++i) { int nfa = finds(i); if(fi[nfa]*sqr[l2 - l1] != se[nfa] && !vis[nfa]) F[++cnt] = i, vis[nfa] = 1; } if(cnt == 0) printf("YES\n"); else { if(cnt > 2) printf("NO\n"); else { if(fi[F[1]]*sqr[l2 - l1] + fi[F[2]]*sqr[l2 - l1]== se[F[2]] + se[F[1]]) { if(mp[(fi[F[1]]*sqr[l2 - l1] - se[F[1]])])printf("YES\n"); else printf("NO\n"); } else printf("NO\n"); } } } return 0; }
51 NOD 1753 相似子串 字符串hash