codeforces 494(Div3) 1003 F.Abbreviation hash+暴力
F. Abbreviation
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output
You are given a text consisting of nn space-separated words. There is exactly one space character between any pair of adjacent words. There are no spaces before the first word and no spaces after the last word. The length of text is the number of letters and spaces in it. wiwi is the ii -th word of text. All words consist only of lowercase Latin letters.
Let's denote a segment of words w[i..j]w[i..j] as a sequence of words wi,wi+1,…,wjwi,wi+1,…,wj . Two segments of words w[i1..j1]w[i1..j1] and w[i2..j2]w[i2..j2] are considered equal if j1−i1=j2−i2j1−i1=j2−i2 , j1≥i1j1≥i1 , j2≥i2j2≥i2 , and for every t∈[0,j1−i1]t∈[0,j1−i1] wi1+t=wi2+twi1+t=wi2+t . For example, for the text "to be or not to be" the segments w[1..2]w[1..2] and w[5..6]w[5..6] are equal, they correspond to the words "to be".
An abbreviation is a replacement of some segments of words with their first uppercase letters. In order to perform an abbreviation, you have to choose at least two non-intersecting equal segments of words, and replace each chosen segment with the string consisting of first letters of the words in the segment (written in uppercase). For example, for the text "a ab a a b ab a a b c" you can replace segments of words w[2..4]w[2..4] and w[6..8]w[6..8] with an abbreviation "AAA" and obtain the text "a AAA b AAA b c", or you can replace segments of words w[2..5]w[2..5] and w[6..9]w[6..9] with an abbreviation "AAAB" and obtain the text "a AAAB AAAB c".
What is the minimum length of the text after at most one abbreviation?
Input
The first line of the input contains one integer nn (1≤n≤3001≤n≤300 ) — the number of words in the text.
The next line contains nn space-separated words of the text w1,w2,…,wnw1,w2,…,wn . Each word consists only of lowercase Latin letters.
It is guaranteed that the length of text does not exceed 105105 .
Output
Print one integer — the minimum length of the text after at most one abbreviation.
Examples
Input
6 to be or not to be
Output
12
Input
10 a ab a a b ab a a b c
Output
13
Input
6 aa bb aa aa bb bb
Output
11
Note
In the first example you can obtain the text "TB or not TB".
In the second example you can obtain the text "a AAAB AAAB c".
In the third example you can obtain the text "AB aa AB bb"
題意:給你n個單詞,編號從1到n,如果在區間[i,j]和其他不與i,j區間重合的區間裡面完全相同,那麼這些所有的完全一樣的區間可以用區間內的每個單詞取首字母,按原來的順序組成新的單詞,至少有兩個完全相同的區間才能將每個區間重組,這個區間可以只有一個單詞,這樣的替換隻能進行一次,問進行這樣的重組後,最少有多少個text(及字母,空格),注意每兩個單詞間都有一個空格,第一個單詞前面沒有,最後一個後面也沒有。
思路:n只有300,O(n^3)的暴力完全可以解決問題,暴力有很多種看他們有直接暴力比較每個區間的單詞,注意用過的區間時不能再用的,我用了比較繁瑣的hash來比較,發現常用的base的單hash真的被卡了,不過不常用的base的單hash還是可以過。
反思:最開始我做的時候讀錯了題意,以為題意是隻要是區間內的單詞相同就可以合併在一起,沒想到是隻能合併一次,只是可以把所有相同的區間合併到一起而已。另外,hash是一個玄學的東西,當字串足夠多的時候單hash難免會衝突從而wa掉,出題人也比較容易卡你,本題的字串一點都不多,不過單hash還是出題人針對性的被卡掉了,我提交過很多次,發現當我的mod=1e9+93是好多base的的單hash都被卡掉了,而mod=1e9+97可以過,所以單hash很容易wa,如果非要用單hash也要用base和mod不常見的,像什麼133,131,233最好別用了,當然雙hash另當別論了。
程式碼:
#include<stdio.h>
#include<string.h>
#include<cmath>
#include<stdlib.h>
#include<time.h>
#include<algorithm>
#include<iostream>
#include<vector>
#include<queue>
#include<bitset>
#include<map>
#include<set>
#define ll long long
#define ull unsigned long long
#define qq printf("QAQ\n");
using namespace std;
const int maxn=1e5+5;
const int inf=0x3f3f3f3f;
const ll base2=133;
const ll base1=251;
const ll mod=1e9+7;
const ll hmod1=1e9+93;
const ll hmod2=1e9+97;
const double e=exp(1.0);
const double pi=acos(-1);
ll sum1[305]={0},sum2[305]={0};
int len[305]={0};
ll quick_pow(ll a,int n,ll hmod)
{
ll ans=1;
while(n)
{
if(n&1)ans=(ans*a)%hmod;
n/=2;
a=(a*a)%hmod;
}
return ans;
}
int main()
{
int n;
string s;
while(scanf("%d",&n)!=EOF)
{
ll ans=0,sum;
for(int i=1;i<=n;i++)
{
cin>>s;
ll a1=0,a2=0;
int l=s.length();
ans+=l;
len[i]=len[i-1]+l;
for(int j=0;j<l;j++)
{
a1=(a1*base1+(ll)s[j])%hmod1;
a2=(a1*base2+(ll)s[j])%hmod2;
}
sum1[i]=(sum1[i-1]*base1+a1)%hmod1;
sum2[i]=(sum2[i-1]*base2+a2)%hmod2;
}
/*ll bit=quick_pow(base1,2,hmod1);
cout<<((sum1[5]-(bit*sum1[3])%hmod1)%hmod1+hmod1)%hmod1<<endl;
cout<<(sum1[2])%hmod1<<endl;
continue;*/
ans+=n-1;
sum=ans;
for(int i=1;i<=n;i++)
{
for(int j=i;j<=n;j++)
{
int num=0,l=j-i+1;
for(int k=j+1;k+l-1<=n;k++)
{
ll bit1=quick_pow(base1,l,hmod1);
ll bit2=quick_pow(base2,l,hmod2);
if((((sum1[j]-(bit1*sum1[i-1])%hmod1)%hmod1)+hmod1)%hmod1==((sum1[k+l-1]-(bit1*sum1[k-1])%hmod1)%hmod1+hmod1)%hmod1)
if((((sum2[j]-(bit2*sum2[i-1])%hmod2)%hmod2)+hmod2)%hmod2==((sum2[k+l-1]-(bit2*sum2[k-1])%hmod2)%hmod2+hmod2)%hmod2)
k+=l,
k--,//區間不能重合
num++;
}
if(num)ans=min(ans,sum-((num+1)*(len[j]-len[i-1]-1)));
}
}
printf("%d\n",ans);
}
return 0;
}