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;
 } 

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值