JZOJ 5485. 【清华集训2017模拟11.26】字符串

来源:互联网 发布:淘宝客api 查询优惠券 编辑:程序博客网 时间:2024/05/17 02:59

题目

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

题解

肯定要DP,问题是怎么设状态。
这个状态需要既表示了位置,又表示了块数,还表示了当前的答案
设法①,设f[i][j]表示做到i,切了j次的答案。这样子顶多撑得下n200.
转移显然。(然而斜率优化可以过n≤1500)
还有一种方法,不考虑位置的严格转移(即i推向i+1),但是状态存的是字符串的位置。
设法②,可以设f[i][j]表示目前分割了i块,答案为i+j的最右边的位置。
这个状态既表示了位置,又表示了块数,还表示了当前的答案
若答案为i+j,说明附加代价为j-1(“附加代价”表示因为字母不同而使答案增加的量)。
那么在转移的时候,由于不允许严格按照相邻位置来转移,那么就可以考虑按照下一段的不同字母个数转移。
g[i][j]表示从第i位始,假设此段的结束点为l,那么s[i~l]中不同字母个数为j的最右边的位置。
这个怎么预处理?
可以发现,g[i][j]g[i+1][j],那么直接暴力就好了。
然而这样肯定有缺点。(跑起来慢死了)
可以先枚举j,枚举左端点i,右端点r可以直接算。复杂度O(25n)

fo(j,1,25){    r=0;    fo(i,1,n)    {        while (r<n && (temp[s[r+1]]||cnt<j))         {            if (temp[s[r+1]]==0) cnt++;//拿个桶标记一下这个字母有没出现过就好了            temp[s[r+1]]++;             r++;        }        g[i][j]=r;temp[s[i]]--;        if (temp[s[i]]==0) cnt--;    }}

设下一段不同字母个数为k,那么附加代价就加上k-1。
转移:

f[i+1][j+k1]=max(f[i+1][j+k1],g[f[i][j]+1][k])

代码

#include<iostream>#include<cstdio>#include<cstring>#include<cmath>#include<algorithm>#define N 100010#define fo(i,a,b) for(i=a;i<=b;i++)#define fd(i,a,b) for(i=a;i>=b;i--)using namespace std;int n,k,K,i,j,m,s,l,x,ans,cnt;int val[N],d[N][26];int f[N][30],g[N][30];int _2[30];char st[N];int getcount(int l,int r){    int i,res=0;    fo(i,0,25)if(d[r][i]-d[l-1][i])res++;    return res;}int main(){    _2[1]=1;fo(i,2,29)_2[i]=_2[i-1]*2;    scanf("%d%d\n",&n,&K);    scanf("%s\n",st+1);    fo(i,1,n){        x=st[i]-'a';        val[i]=x;        fo(j,0,25)d[i][j]=d[i-1][j];        d[i][x]++;    }    fo(i,0,26)g[n][i]=g[n+1][i]=n;    fd(i,n-1,0){        fo(j,0,26){            g[i][j]=g[i+1][j];            while(g[i][j]>i && getcount(i,g[i][j])>j)g[i][j]--;        }    }    f[0][0]=0;    fo(i,0,K-1)        fo(j,0,25)            fo(k,1,26){                if(j+k>25)break;                f[i+1][j+k-1]=max(g[f[i][j]+1][k],f[i+1][j+k-1]);            }    fo(i,0,26)        if(f[K][i]==n){            printf("%d",K+i);            break;        }    return 0;}
阅读全文
1 0
原创粉丝点击