清华集训2017模拟之字符串

3G基础知识

5人已加入

描述

  Description  

一个字符串的权值是这个串包含的不同字符个数。

  给定一个长度为n的字符串,把它分为k个连续非空字段,每个字符必须在某一段中,最小化字符串的权值和。

  Input

  第一行两个数n,k,含义如题所述。

  接下来一行一个长度为n的字符串,保证仅包含小写英文字母。

  Output

  输出最小权值。

  Sample Input

  输入1:

  12 3

  abaacdddfe

  输入2:

  50 35

  acbdcfabcaedscdbcsbacbdcbbacjacbkabcjadkcbsjkckkza

  Sample Output

  输出1:

  6

  样例解释1:

  一种最优方案是分为:”abaa”, “cddd”和”feff”。

  输出2:

  39

  Data Constraint

  对于10%的数据,n《=10。

  对于30%的数据,n《=200。

  对于50%的数据,n《=1500。

  对于另外20%的数据,仅包含a和b两种字母。

  对于100%的数据,1《=k《=n《=100,000。

  Solution

  一个很显然的dp:f[i][j]表示到位置i,分为了j段,需要的最小代价

  这有50分

  可以发现,答案最大为段数+25

  那么代价不会很大,可以放到状态中

  状态改成f[i][j]表示分了i段,代价为i+j最右可以到哪里

  预处理一个a[i][j]表示从位置i出发,花代价为j,最右可以到哪里

  然后随意转移一下

  但是,这么做是有bug的(数据里没有,所以这样就可以A了)

  如果到某一次,最后剩下的位数已经不够分K段了,前面就不能延伸到最后,这个取个min就行了

Code

  #include《cstdio》

  #include《cstring》

  #include《algorithm》

  #define fo(i,a,b) for(int i=a;i《=b;i++)

  #define fd(i,a,b) for(int i=a;i》=b;i--)

  #define N 101000

  using namespace std;

  int n,K,a[N][27],f[N][27],s[N],bz[27],ans;

  int main()

  {

  scanf(“%d%d\n”,&n,&K);

  fo(i,1,n)

  {

  char c=getchar();

  s[i]=c-97;

  }

  fo(k,1,26)

  {

  memset(bz,0,sizeof(bz));

  int x=0,y=0;

  while(y《=k&&x《=n)

  {

  x++;

  bz[s[x]]++;if(bz[s[x]]==1) y++;

  }

  a[0][k]=x-1;

  fo(i,2,n+1)

  {

  bz[s[i-1]]--;if(bz[s[i-1]]==0) y--;

  while(y《=k&&x《=n)

  {

  x++;

  bz[s[x]]++;if(bz[s[x]]==1) y++;

  }

  a[i-1][k]=x-1;

  }

  }

  memset(f,255,sizeof(f));

  f[0][0]=0;

  fo(k,0,26)

  {

  fo(i,0,K-1)

  if(f[i][k]》=0)

  {

  fo(k1,1,26-k) f[i+1][k+k1-1]=min(n-K+i+1,max(f[i+1][k+k1-1],a[f[i][k]][k1]));

  }

  }

  fd(k,26,0) if(f[K][k]==n) ans=k+K;

  printf(“%d\n”,ans);

  }

打开APP阅读更多精彩内容
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉

全部0条评论

快来发表一下你的评论吧 !

×
20
完善资料,
赚取积分