您的位置:首页 > 产品设计 > UI/UE

CF CROC 2016 Intellectual Inquiry

2016-05-06 14:54 537 查看
题目链接:http://codeforces.com/contest/655/problem/E

大意是Bessie只会英文字母表中的前k种字母,现在有一个长度为m+n的字母序列,Bessie已经知道了前m个字符,问如何填充剩下的n个字符,使得整个序列的不同子序列数目最大。当然所有字母都得是Bessie会的前k个字母。

两个月前比赛的时候做的,是一道不错的题。

关于子序列个数的计算

令dp[i]表示前i个数字组成的序列中子序列的个数,

则对于第i个数字a[i]来说,dp[i]来源于两种情况的转化:

序列中前一个数字为a[i],记这种情况为s1以及前一个数字不为a[i],计这种情况为s2。

dp[i]=s1+s2*2=2*dp[i-1]-s1

可以这么理解,首先之前的子序列个数是dp[i-1],这些子序列直接都加一个a[i],一定是可以的。这只是新答案中以a[i]为结尾的情况,那么不以a[i]为结尾的情况,直接就是继承自原来的s2。

所以可以看出要使得dp值尽量大,就要让每一次因为重复需要减去的s1值尽可能小,也就是要让a[i]距离上一次出现a[i]尽可能地远。

根据前m个字符信息,计算可以使用的k个字母的最后出现的位置,根据这个来进行排序,使得最后出现的位置越小的字母排在越前面。

对于剩下的n个需要填充的字符,直接按照排出来的k个字母顺序,循环使用。

最后按照上述子序列计算方式来进行计算。

#include <iostream>
#include <vector>
#include <algorithm>
#include <string>
#include <string.h>
#include <stdio.h>
#include <math.h>
#include <queue>
#include <stack>
#include <map>
#include <set>

using namespace std;

const int N=2234567;

const long long MOD=1e9+7;

char s
;
struct Node {
char ch;
int pos;
Node(){
pos=-1;
}
bool operator < (const Node &o) const {
return pos<o.pos;
}
}node[30];
long long cnt[30];
int main() {
for (int i=0;i<26;i++)
node[i].ch=char('a'+i);
int n,k;
scanf("%d %d",&n,&k);
scanf("%s",s);
int m=strlen(s);
for (int i=0;i<m;i++) {
int id=s[i]-'a';
node[id].pos=i;
}
sort(node,node+k);
for (int i=m,cnt=0;i<m+n;i++,cnt++) {
if (cnt>=k) cnt=0;
s[i]=node[cnt].ch;
}
s[m+n]=0;
//puts(s);
long long ret=1;
memset(cnt,0,sizeof cnt);
for (int i=0;i<m+n;i++) {
long long tmp=ret;
int id=s[i]-'a';
ret=ret*2-cnt[id];
ret+=MOD;
ret%=MOD;
while (ret<0) ret+=MOD;
cnt[id]=tmp;
}
printf("%I64d\n",ret);
return 0;
}


View Code
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: