记录编号 146723 评测结果 AAAAAAAAAA
题目名称 [SRM 467] 均匀字符串 最终得分 100
用户昵称 Gravatarcstdio 是否通过 通过
代码语言 C++ 运行时间 0.046 s
提交时间 2015-01-19 11:05:40 内存使用 58.69 MiB
显示代码纯文本
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int HSIZE=50007;
typedef unsigned US;
typedef long long LL;
typedef long double LDB;
//我们用一个unsigned去表示一个状态,每四个bit一位
int n,d;//相邻n位中不同的不能超过d种
class Node{
public:
	unsigned s;
	LDB f;
	int nxt;
};
class Hash_Map{
public:
	int head[HSIZE];
	Node lis[HSIZE];
	int tot;
	LDB& operator [] (unsigned s){
		int key=s%HSIZE,x;
		for(x=head[key];x;x=lis[x].nxt){
			if(lis[x].s==s) return lis[x].f;
		}
		lis[++tot]=(Node){s,-1,head[key]};//-1代表它不存在
		head[key]=tot;
		return lis[tot].f;
	}
};
Hash_Map F[51];
unsigned re_label(unsigned s){
	static int lis[10];
	memset(lis,0,sizeof(lis));
	int ans=0,tot=0;
	for(int i=0;i<32;i+=4){
		int t=(s>>i)&15;
		if(!t) break;
		if(!lis[t]) lis[t]=++tot;
		ans|=(lis[t]<<i);
	}
	return ans;
}
void calc_len(unsigned s,unsigned &len,unsigned &mx){
	len=mx=0;
	for(int i=0;i<32;i+=4){
		unsigned t=(s>>i)&15;
		if(!t) break;
		len++,mx=max(mx,t);
	}
}
LDB DP(unsigned s,int len){//在s之后还要走len位
	s=re_label(s);
	LDB &ans=F[len][s];
	if(ans>=0) return ans;
	ans=0;
	unsigned m,mx;
	calc_len(s,m,mx);
	if(mx>d) return ans=0;
	if(len==0) return ans=1;
	//考虑加上一个新的
	if(mx<d){
		if(m<n-1) ans+=(26-mx)*DP(s|((mx+1)<<m*4),len-1);
		else ans+=(26-mx)*DP((s>>4)|((mx+1)<<(n-2)*4),len-1);
	}
	//考虑用一个旧的
	for(unsigned i=1;i<=mx;i++){
		if(m<n-1) ans+=DP(s|(i<<m*4),len-1);
		else ans+=DP((s>>4)|(i<<(n-2)*4),len-1);
	}
	return ans;
}
unsigned turn_US(string &str){//若过长则只取后n-1位
	static int lis[26];
	int tot=0;
	memset(lis,0,sizeof(lis));
	int m=str.size(),start=max(0,m-(n-1));
	unsigned ans=0;
	for(int i=0;i<m-start;i++){
		int c=str[i+start]-'a';
		if(!lis[c]) lis[c]=++tot;
		ans|=(lis[c]<<i*4);
	}
	return ans;
}
bool check_legal(string &str){//检查一个字符串是否合法
	static int cnt[26];
	memset(cnt,0,sizeof(cnt));
	int now=0;
	for(int i=0;i<str.size();i++){
		int c=str[i]-'a';
		if(cnt[c]==0) now++;
		cnt[c]++;
		if(i>=n){
			c=str[i-n]-'a';
			cnt[c]--;
			if(cnt[c]==0) now--;
		}
		if(now>d) return false;
	}
	return true;
}
LDB calc(string str,int len){//以str为前缀,str后面还有len位的合法字符串数量
	if(!check_legal(str)) return 0;//如果str本身不合法
	unsigned s=turn_US(str);
	return DP(s,len);
}
LDB calc_less(string seed,int L){
	string now="";
	LDB ans=0;
	for(int i=0;i<L;i++){
		for(char c='a';c<seed[i];c++){
			ans+=calc(now+c,L-1-i);
		}
		now+=seed[i];
		if(!check_legal(now)) break;//这里测试时得取n位
		while(now.size()>=n) now.erase(now.begin());
	}
	return ans;
}
class NextHomogeneousStrings{
public:
	string getNext(int d_,int n_,string seed,LL K){
		K++;
		//找>=seed且第K小的字符串
		d=d_,n=n_;
		int L=seed.size();
		string ans;
		int left;
		for(int i=L-1;i>=0;i--){//试图在第i位上进行更改
			char low=(i==L-1?seed[i]:seed[i]+1);
			for(char c=low;c<='z';c++){
				LDB now=calc(seed.substr(0,i)+c,L-1-i);
				if(now<K) K-=now;
				else{
					ans=seed.substr(0,i)+c,left=L-1-i;
					goto OUT;
				}
			}
		}
		return "";
		OUT:;
		//现在我们需要取以ans为前缀的第K小字符串
		for(int i=1;i<=left;i++){
			for(char c='a';c<='z';c++){
				LDB now=calc(ans+c,left-i);
				if(now<K) K-=now;
				else{
					ans+=c;
					break;
				}
			}
		}
		return ans;
	}
};
int main(){
	freopen("homogeneous.in","r",stdin);
	freopen("homogeneous.out","w",stdout);
	NextHomogeneousStrings me;
	int d,n;
	LL k;
	string seed;
	cin>>d>>n>>seed>>k;
	cout<<me.getNext(d,n,seed,k)<<endl;
	//cout<<me.getNext(1,2,"aaa",3)<<endl;
	return 0;
}