第十一届山东省大学生程序设计竞赛(Birthday Cake)
做法双哈希
原文:链接:https://ac.nowcoder.com/acm/contest/16092/F
Moca’s birthday is coming up, and her friend Ran is going to the Yamabuki bakery to order a birthday cake for her.
Yamabuki bakery provides nn kinds of cake. Since Ran knows that Moca is the Yamabuki Bakery’s 11-st fan and can eat a lot of food, she intends to order two cakes and put them together into a big cake. The cake made by Yamabuki bakery can be formed by a string consisting of lowercase Latin letters, which describes the toppings on the cake, such as strawberries and chocolate. Putting two cakes together is the concatenation of two corresponding strings. For example, the result of putting cake abab and cake cabccabc together is a big cake abcabcabcabc.
To make it easier to share the cake, Ran will choose two cakes and put them together into a big cake which can be divided in half into two identical pieces. For example, cake abcabcabcabc will be divided in half into two cakes abcabc, but cake abbcabbc will be divided in half into two different cakes abab and bcbc. Notice that Ran can not reverse the cake, which means that cake abbaabba will be divided into two different cakes abab and baba.
Can you help Ran figure out how many different pairs of cakes meet the above condition?
由题意可知:有几对字符串可以组成前后一样的字符串,类似于abcabc此类;
解法:if(字符串前后缀相同) 就检查去掉前后缀之后的字符串出现过几次ans+=这个次数;
举个栗子: cabc 这个字符串前后缀 c 相同 就看ab出现过几次 ab和cabc就可以组成abcabc;
#include<bits/stdc++.h>
#include<cstring>
using namespace std;
#define ull unsigned long long
#define pll pair<ull,ull>
const int maxn=4e5+5;
ull hs1[maxn],hs2[maxn],pec=131,peac1[maxn],peac2[maxn];
ull mod1=1e9+7,mod2=1e9+11;
pll res[maxn];
map<pll, ull> cnt;
ull get1(int l,int r){
return (hs1[r]-hs1[l-1]*peac1[r-l+1]%mod1+mod1)%mod1;//一定要去两次mod
}
ull get2(int l,int r){
return (hs2[r]-hs2[l-1]*peac2[r-l+1]%mod2+mod2)%mod2;
}
pll get(int l,int r){
return {get1(l,r),get2(l,r)};
}
int id=0;
int main(){
peac1[0]=1;
peac2[0]=1;//初始化进制
for(int i=1;i<maxn;i++) peac1[i]=peac1[i-1]*pec%mod1;
for(int i=1;i<maxn;i++) peac2[i]=peac2[i-1]*pec%mod2;
int n;
cin>>n;
while(n--){
char s[maxn];
cin>>s+1;
int len=strlen(s+1);
for(int i=1;i<=len;i++){
hs1[i]=(hs1[i-1]*pec%mod1+(s[i]-'a'+1))%mod1;
hs2[i]=(hs2[i-1]*pec%mod2+(s[i]-'a'+1))%mod2;
}
cnt[{hs1[len],hs2[len]}]++;//记录出现的字符串双哈希
for(int i=1;i+i<len;i++){
if(get(1,i)==get(len-i+1,len)){ //前后缀双哈希值相等
res[++id]=get(i+1,len-i); //存入res数组
}
}
}
ull ans=0;
for(int i=1;i<=id;i++) { //ans+=出现次数即为所得
ans+=cnt[res[i]];
}
for(auto it : cnt) ans += it.second * (it.second - 1) / 2;
//如果是相同的字符串就可以组成((n-1)*n)/2个答案
cout<<ans<<'\n';
}
当我们遇见哈希题时 如果单哈希解决不了 可以试试双哈希来解决 现在大多数出题人喜欢卡单哈希T_T~~~~~
祝大家天天AC