一道codeforces上的题目。
题目大意:
定义有k个不同的字符的字符串为好字符串。现在给出一个字符串,求解对该字符串的每个前缀Si至少是多少个好字符串的连接,若不能由好字符串连接而成则输出-1。
例:k = 2
abac至少是ab和ac这两个好字符串的连接。
字符串长度<=2e5
看了一下网上的题解都是这样子的
DP+数据结构
尺取+dp+线段树
比较麻烦。
列出基本DP式:f[i]={f[j]+1} S(j+1)-i为好串
显然对于i,满足条件的j的区间是单调不降的,因此,可以放一个指针j在i后面,若j-i的串超过限制或f[j]==-1,j直接向前跳,因为满足条件的j区间单调不降,所以前面的f[]是没用的。由于f[]单调不降,所以跳到k>=num就停,然后更新答案,这样一定最优。
代码:
#include<iostream> #include<cstring> #include<string> #include<cstdio> #include<iomanip> #include<algorithm> #include<cmath> #include<vector> #include<set> #include<map> #include<cstdlib> using namespace std; #define ll long long #define up(i,j,k) for(int i=(j);i<=(k);i++) #define cmin(a,b) a=min(a,b) #define cmax(a,b) a=max(a,b) #define pii pair<int,int> const int maxn=400010,inf=1e9,mod=1e9+7; int read(){ int ch=getchar(),x=0,f=1; while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar(); return f*x; } int f[maxn]; char s[maxn]; int k,n; int vis[26],num=0; void add(int x){ vis[x]++; if(vis[x]==1)num++; } void erase(int x){ vis[x]--; if(!vis[x])num--; } int main(){ k=read();scanf("%s",s+1);n=strlen(s+1); int sum=-1,head=0; for(int i=1;i<=n;i++){ add(s[i]-'a'); while((num>k||f[head]==-1)&&head<i)erase(s[++head]-'a'); if(f[head]==-1||num!=k)f[i]=-1; else f[i]=f[head]+1; } up(i,1,n)printf("%d%c",f[i],i==n?' ':' '); return 0; }