青云的服务器密钥
- 1000ms 131072K
青云给每台服务器设置了一个由小写字母a-z
组成的密钥。密钥的易破解程度定义如下:
对于密钥 ,我们需要首先计算其对应的 数组。对于任意的 ,。也就是最长的前缀等于后缀的长度。
则密钥的易破解程度为 ,值越小,易破解程度越高。
现在已知密钥的 中每个小写字母的字符个数,小明想知道易破解程度最高是多少?
输入格式
第一行一个正整数 表示数据的组数。每组数据一行, 个非负整数 ,表示密钥中每个小写字母的个数。
输出格式
一共输出 行,每行一个整数,为每组输入对应的易破解程度最高的结果。
样例输入
1 2 2 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
样例输出
1
提示信息
abba
是一个符合输入的密钥,除了 ,其他都是 ,因此 。
题意:就是给定一个只含26个小写字母的序列,让你组合,使得它所有的πi值之和最小,其中πi的定义是在子序列1到i这段,在找到一个L的位置,使得以L为子序列的分界,从1正数开始L个与从i倒数L个的序列相同,L即为此时的πi值。
题目链接:青云的服务器密钥
解题思路:解题首先要看懂题目,刚开始连题目看了好久。分两种情况:
1.只有一种字母。
这时,当字母数cnt>=2,对应的π值应该为cnt-1,比如 “aaaaa",π1=0,π2=1(a,a),π3=2(aa,aa(中间重合了一个a)),π4=3(123,432(对应a的位置)),π2=4(aaaa,aaaa(表示的含义前面已经说了)),相加结果为10,
不难发现规律,就为一个以1为首项,cnt-1为尾项的等差数列和。
2.两种或者以上的字母。
想要让总和最小,那么肯定想办法让他子序列重合的部分越少,因为子序列比较的位置是从1开始(这点是固定的),那么我们就把某个字母安排在这,它同种类的其他字母安排到最后,那么前面不含这个字母的部分的π值都将为0,从开始出现这个字符,才有π值,且只能为1,因为后缀只能和1号位置的匹配,这样答案就应该是这个字母出现次数cnt-1。
代码:
//青云的服务器密钥
//链接:http://nanti.jisuanke.com/t/11162
#include
#include
using namespace std;
int a[30];
int main()
{
int T,i,ans,cnt,mx;
cin>>T;
while(T--){
mx=0x3f3f3f3f;
for(i=cnt=0;i<26;i++){
cin>>a[i];
if(a[i]){
cnt++; //记住单词的种类
mx=min(mx,a[i]); //更新最小单词出现的次数
}
}
if(cnt==0){
ans=0;
}
else if(cnt==1){
ans=mx*(mx-1)/2;
}
else ans=mx-1;
cout<
<