2021山东省赛f.Birthday Cake(双哈希考虑贡献)
Posted 吃花椒的妙酱
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021山东省赛f.Birthday Cake(双哈希考虑贡献)相关的知识,希望对你有一定的参考价值。
题目大意:给n个字符串,求有多少对字符串可以组成平方串(可以分为两个一样的子串)
思路:考虑贡献,哈希/kmp
对于一个字符串,有两种情况,一种是出现公共前后缀,然后接上另一个字符串(绿色),我们枚举公共前后缀的长度(黄色部分,哈希/kmp实现),然后考虑黑色部分的贡献,如果之前黑色部分出现过cnt次,那本次黑色的贡献则为cnt,以此类推。字符串的查询和存储我们用哈希实现。
情况二,对于整个字符串(绿色字符串),我们不仅要加上之前出现过和他一样的字符串的出现次数(也可以理解为情况一时公共前后缀为0),还要计算上它作为其他串的中间部分的贡献(和上面字符串组成平方串)。
注意:1,此题需要双哈希才能过,用pair存舒服一点
2,区别回文和公共前后缀,最后一个for循环里,如果当前不是公共前后缀那么也不能break,可能后面还会有,和回文串不一样的性质!!(调了一晚上)
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <map>
#include <vector>
#include <queue>
using namespace std;
#define _for(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define _rep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define mst(v,s) memset(v,s,sizeof(v))
#define pb push_back
#define IOS ios::sync_with_stdio(false)
#define int long long
#define INF 0x3f3f3f3f3f3f3f3f
#define all(v) v.begin(),v.end()
typedef long long ll;
const int N=4e5+10;
const int mod1 = 1e9+7;
const int mod2 = 998244353;
map<pair<int ,int > ,int > mp1,mp2;//整个串和内部
pair <int,int > pi;
int p=101;
int n;
int hash1[N];
int hash2[N];
ll qsm(int a, int b ,int mod)
{
ll ans=1,temp=a;
while( b )
{
if( b&1) ans = (ans * temp ) %mod;
temp = ( temp * temp)%mod;
b>>=1;
}
return ans%mod;
}
pair<int,int> get(int l,int r)
{
int x= (hash1[r]+mod1 - hash1[l-1]*qsm(p,r-l+1,mod1)%mod1)%mod1;
int y= (hash2[r]+mod2 - hash2[l-1]*qsm(p,r-l+1,mod2)%mod2)%mod2;
return make_pair(x,y);
}
signed main()
{
// /!!!
// freopen("data.txt","r",stdin);
// !!!
// IOS;
cin>>n;
ll ans = 0;
_for(i,1,n){
string s;cin>>s;
int len = s.size();
for(int i=1;i<=len;++i){
hash1[i] = (hash1[i-1]*p+s[i-1]-'a'+1)%mod1;
hash2[i] = (hash2[i-1]*p+s[i-1]-'a'+1)%mod2;
}
pair<ll,ll> temp = make_pair(hash1[len],hash2[len]);
ans += mp1[temp]; // 加上跟该串一模一样的
mp1[temp]++;
ans += mp2[temp]; // 加上内部和{该串整串}一样的串
for(int i=1;2*i<len;++i){
pair<int,int> x= get(1,i);
pair<int,int> y= get(len-i+1,len);
if(x==y){
// 前后缀一样
pair<int,int> z = get(i+1,len-i);
// 中间部分
ans += mp1[z]; // 加上整串和该串内部一样的串
mp2[z]++;
}
}
}
cout<<ans;
}
以上是关于2021山东省赛f.Birthday Cake(双哈希考虑贡献)的主要内容,如果未能解决你的问题,请参考以下文章
2021山东省赛 M - Matrix Problem 看样例+构造