JZOJ 5485. 【清华集训2017模拟11.26】字符串
2017-12-01 11:50
471 查看
题目
一个字符串的权值是这个串包含的不同字符个数。给定一个长度为n的字符串,把它分为k个连续非空字段,每个字符必须在某一段中,最小化字符串的权值和。
题解
肯定要DP,问题是怎么设状态。这个状态需要既表示了位置,又表示了块数,还表示了当前的答案。
设法①,设f[i][j]表示做到i,切了j次的答案。这样子顶多撑得下n≤200.
转移显然。(然而斜率优化可以过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+k−1]=max(f[i+1][j+k−1],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 ; 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 [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; }
相关文章推荐
- [JZOJ5485]【清华集训2017模拟11.26】字符串
- 【清华集训2017模拟11.26】字符串
- JZOJ5483. 【清华集训2017模拟11.26】简单路径
- [jzoj]5483. 【清华集训2017模拟11.26】简单路径
- [jzoj]5484. 【清华集训2017模拟11.26】快乐树(树形DP)
- JZOJ 5484. 【清华集训2017模拟11.26】快乐树
- JZOJ5484. 【清华集训2017模拟11.26】快乐树
- JZOJ 5483. 【清华集训2017模拟11.26】简单路径
- JZOJ5485. 【清华集训2017模拟11.26】字符串
- JZOJ 5489. 【清华集训2017模拟11.28】海明距离
- 【JZOJ5295】【清华集训2017模拟】Create
- 【JZOJ 5282】【清华集训2017模拟】等差划分数
- JZOJ 5496. 【清华集训2017模拟12.09】Tree
- JZOJ5498. 【清华集训2017模拟12.10】大佬的难题
- 【JZOJ 5276】【清华集训2017模拟】神奇的玩具
- jzoj5317 【清华集训2017模拟8.19】func (寻找性质)
- [JZOJ5498]【清华集训2017模拟12.10】大佬的难题
- 5483. 【清华集训2017模拟11.26】简单路径
- 【JZOJ5296】【清华集训2017模拟】Sequence
- JZOJ 5500. 【清华集训2017模拟12.10】营养餐