卧薪尝胆,厚积薄发。
Intellectual Inquiry
Date: Thu Jul 19 17:15:23 CST 2018
In Category:
NoCategory
Description:
给定一个长度为
$ n $
的字符串
$ S$
,你可以在字符串
$ S $
后再添加
$ m $
个字符, 使得新字符串
$ T $
所包含的不同的子序列数量尽量多。求最多的不同子序列数量。
$n+m\le 2\times10^5$
Solution:
记
$last_c$
表示字符
$c$
上一次出现的位置,则在后面添加
$c$
能产生的新子序列就是在没有在
$[1,last_c)$
中出现的子序列添上
$c$
得到的,记
$F_i$
表示以第
$i$
位为结尾的新出现的不同子序列个数,
$G_i$
是
$F_i$
前缀和,于是有
$F_i=G_{i-1}-G_{last_{c_i}-1}$
,于是贪心的选
$last_{c_i}$
最小的即可。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<map>
#include<cstring>
using namespace std;
int n,m;
typedef long long ll;
int last[27];
#define MAXN 1000010
ll G[MAXN << 1],F[MAXN << 1],*g = G + 1,*f = F + 1;
char c[MAXN];
#define MOD 1000000007
int main()
{
scanf("%d%d",&n,&m);
scanf("%s",c + 1);
int l = strlen(c + 1);
g[-1] = f[-1] = 0;
g[0] = f[0] = 1;
for(int i = 1;i <= l;++i)
{
f[i] = (g[i - 1] - g[last[c[i] - 'a' + 1] - 1] + MOD) % MOD;
g[i] = (g[i - 1] + f[i]) % MOD;
last[c[i] - 'a' + 1] = i;
}
for(int i = l + 1;i <= l + n;++i)
{
int minlast = 0x3f3f3f3f,p;
for(int j = 1;j <= m;++j)
{
if(last[j] < minlast)
{
minlast = last[j];
p = j;
}
}
f[i] = (g[i - 1] - g[minlast - 1] + MOD) % MOD;
g[i] = (g[i - 1] + f[i]) % MOD;
last[p] = i;
}
cout << g[n + l] << endl;
return 0;
}
In tag:
算法-贪心
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡