codeforces上某题

 

一道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
#include
#include<string>
#include
#include
#include
#include
#include
#include<set>
#include
#include
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
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'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?'\n':' ');
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/chadinblog/p/9201290.html

你可能感兴趣的:(数据结构与算法)