Loading

CF1469E A Bit Similar

CF1469E A Bit Similar

因为这道题上了一百多分呢,刷新了div.2最高记录。如果我A题不挂两发直接上Master了/kk

这是一种没有细节,只用敲863B的无脑方法,非常适合在打CF的时候使用。

这题解法好多啊,而且怎么有2400啊,感觉偏高>_<


看完题第一反应,一个串不可行,当且仅当它是原串某个长度为 \(k\) 的子串的反串。

再看几眼灵光一闪直接就会了。把原串字符串哈希了,把每一个长度为 \(k\) 的串的反串丢进哈希表。然后维护一个二进制 \(k\) 位的大整数,初始为 \(0\),每次加 \(1\) ,模拟进位,动态维护这个新串的哈希值(这样显然字典序最小),直到这个串的哈希值不在原串出现,或者这个串已经是 \(1111\cdots111\) 并且哈希值还是出现了,那就无解。

进位直接均摊 $O(\text{次数}) $ ,显然最多修改 \(n-k+1\) 次。哈希为了不被卡用了 map ,虽然由于模数是自己设的不太能卡。所以复杂度大常数 \(O(n\log n)\) ,CF跑跑还是很轻松的,只用了 \(800ms\)

真的非常无脑。只不过第一次写这个动态维护哈希,而且还是自己yy出来的,有点心虚。或许很多人也是第一次见到这玩意,还是详细讲一下吧:

设当前串的哈希值为 \(h\)

  • 末尾加 \(1\) ,那么 \(h+=1\)

  • 如果第 \(i\) 位要进位,那么这一位减少 \(2\) ,下一位加 \(1\)\(h+=base^{i+1}-2base^i\)

其实挺easy的。

什么?可以只考虑最后 \(20\) 位?然后一群人因为没考虑前面的 \(0\) fst了?这种方法完全没事/cy,毫无细节,好写多了(

你可能会问为啥这种东西你只写了863B。

因为,我 有 板 子 /cy。字符串哈希什么的直接拉下来就能用。实际3.6k

你可能会问CF用哈希不怕被卡吗?

  • Div.2 的rank1用的是1e7模数单哈希,我和同学一起叉了 \(2h\) 叉不掉。应该有很多人尝试叉他了,但是他活的好好的。
  • 你有本事把我这个hash叉掉,我请你吃饭。
#include<bits/stdc++.h>
using namespace std;
#define fi first
#define se second
#define mkp(x,y) make_pair(x,y)
#define pb(x) push_back(x)
#define sz(v) (int)v.size()
typedef long long LL;
typedef double db;
template<class T>bool ckmax(T&x,T y){return x<y?x=y,1:0;}
template<class T>bool ckmin(T&x,T y){return x>y?x=y,1:0;}
#define rep(i,x,y) for(int i=x,i##end=y;i<=i##end;++i)
#define per(i,x,y) for(int i=x,i##end=y;i>=i##end;--i)
inline int read(){
	int x=0,f=1;char ch=getchar();
	while(!isdigit(ch)){if(ch=='-')f=0;ch=getchar();}
	while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
	return f?x:-x;
}
struct Rand{
	unsigned long long sa,sb,sc;
	static const int basic=(1<<30)-1;
	Rand(){
		srand(time(0));
		sa=1ull*::rand()*::rand();
		for(int i=1,up=::rand()%100;i<=up;++i)::rand();
		srand(::rand()^clock());
		sb=1ull*::rand()*::rand();
		for(int i=1,up=::rand()%100;i<=up;++i)::rand();
		srand(::rand()^clock());
		sc=1ull*::rand()*::rand();
	}
	void init(){
		srand(time(0));
		sa=1ull*::rand()*::rand();
		for(int i=1,up=::rand()%100;i<=up;++i)::rand();
		srand(::rand()^clock());
		sb=1ull*::rand()*::rand();
		for(int i=1,up=::rand()%100;i<=up;++i)::rand();
		srand(::rand()^clock());
		sc=1ull*::rand()*::rand();
	}
	inline int rand(){
		sa^=sa<<32,sa^=sa>>13,sa^=sa<<1;
		unsigned long long t=sa;
		sa=sb,sb=sc,sc^=t^sa;
		return static_cast<int>(sc&basic)+1;
	}
	int rad(int l,int r){return rand()%(r-l+1)+l;}
};

template<int N>
struct String_Hash{

static const int O=N+5;
LL H1[O],H2[O],pw1[O],pw2[O],mod1,mod2;
int base1,base2;

String_Hash(){
	static const int base[8]={31,37,41,43,47,53,59,61};
	static const LL mod[8]={100000000000031ll,100000000000367ll,100000000000169ll,100000000000261ll,
	10000000000000069ll,10000000000000639ll,10000000000000753ll,10000000000000669ll};
	static Rand maker;
	base1=base[maker.rand()&7];
	while((base2=base[maker.rand()&7])==base1);
	mod1=mod[maker.rand()&7];
	while((mod2=mod[maker.rand()&7])==mod1);
	pw1[0]=1;for(int i=1;i<=N;++i)pw1[i]=pw1[i-1]*base1%mod1;
	pw2[0]=1;for(int i=1;i<=N;++i)pw2[i]=pw2[i-1]*base2%mod2;
}
void insert(char*str,int n){
	H1[0]=H2[0]=0;
	for(int i=1;i<=n;++i)H1[i]=(H1[i-1]*base1+str[i]-'0'+1)%mod1;
	for(int i=1;i<=n;++i)H2[i]=(H2[i-1]*base2+str[i]-'0'+1)%mod2;
}
LL mul(LL x,LL y,LL mod){
	LL res=x*y-(LL)((long double)x/mod*y+0.5)*mod;
	return res<0?res+mod:res;
}
pair<LL,LL>Hash_val(int l,int r){
	LL v1=(H1[r]-mul(H1[l-1],pw1[r-l+1],mod1)+mod1)%mod1;
	LL v2=(H2[r]-mul(H2[l-1],pw2[r-l+1],mod2)+mod2)%mod2;
	return mkp(v1,v2);
}

};
const int N=1000005;
String_Hash<N>hs;
int n,k,ans[N];
char S[N],T[N];
void Main(){
	scanf("%d%d%s",&n,&k,S+1);
	for(int i=1;i<=n;++i)T[i]='1'-S[i]+'0';
	map<pair<LL,LL>,bool>mp;
	hs.insert(T,n);
	for(int i=1;i<=n-k+1;++i)mp[hs.Hash_val(i,i+k-1)]=1;
	LL h1=0,h2=0;
	for(int i=1;i<=k;++i)h1=(h1*hs.base1+1)%hs.mod1;
	for(int i=1;i<=k;++i)h2=(h2*hs.base2+1)%hs.mod2;
	for(int i=0;i<=k;++i)ans[i]=0;
	for(int i=0;i<=n-k+1;++i){
		if(!mp[mkp(h1,h2)]){
			puts("YES");
			for(int j=1;j<=k;++j)putchar(ans[j]+'0');
			puts("");
			return;
		}
		++ans[k],h1=(h1+1)%hs.mod1,h2=(h2+1)%hs.mod2;
		int j=k;
		while(ans[j]>1){
			ans[j]=0,++ans[j-1];
			h1=(h1+hs.pw1[k-j+1]-2ll*hs.pw1[k-j]%hs.mod1+hs.mod1)%hs.mod1;
			h2=(h2+hs.pw2[k-j+1]-2ll*hs.pw2[k-j]%hs.mod2+hs.mod2)%hs.mod2;
			--j;
		}
		if(j<=0)break;
	}
	puts("NO");
}
signed main(){for(int T=read();T;--T)Main();}
posted @ 2021-01-04 19:53  zzctommy  阅读(113)  评论(0编辑  收藏  举报