【题解】CF1129C Morse Code

CF1129C Morse Code

\(\text{Solution:}\)

考虑直接 \(O(n^2)\)\(dp.\) 如果没有重复的限制,那么有一个简单做法:

依次加入 \(i,\) 枚举所有后缀 \(j,\) 大力 \(dp\) 出方案数。

f[i][j]=Add(f[i][j],f[i-1][j],f[i-2][j],f[i-3][j],f[i-4][j])

对应几种不同状况。那么如何考虑重复?

考虑用哈希判重。对于枚举到的所有后缀,考虑每次 \(dp\) 完就直接在哈希表里面记录对应的 \(dp\) 值。这样就可以达到判重的目的。

但是这里要注意,这里的判重一定要准确对应到字符串上,而不仅仅是一个对于后缀区间上的哈希。一定是要在字符上的重复才不计数,并且:

对应一定要按顺序划分,比如 设 \(f[i][j]\) 是以 \(i\) 为结尾的区间,那么转移应当从右往左划分。而对于 \(dp\) 值的获取直接从之前的哈希表里面找即可。

注意哈希表的实现,卡空间的同时注意时间和空间的常数。这题双哈希过不了,单哈希需要配合哈希表。

#pragma GCC optimize(3)
#pragma GCC optimize(2)
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#pragma GCC optimize("Ofast")
#pragma GCC optimize("inline")
#pragma GCC optimize("-fgcse")
#pragma GCC optimize("-fgcse-lm")
#pragma GCC optimize("-fipa-sra")
#pragma GCC optimize("-ftree-pre")
#pragma GCC optimize("-ftree-vrp")
#pragma GCC optimize("-fpeephole2")
#pragma GCC optimize("-ffast-math")
#pragma GCC optimize("-fsched-spec")
#pragma GCC optimize("unroll-loops")
#pragma GCC optimize("-falign-jumps")
#pragma GCC optimize("-falign-loops")
#pragma GCC optimize("-falign-labels")
#pragma GCC optimize("-fdevirtualize")
#pragma GCC optimize("-fcaller-saves")
#pragma GCC optimize("-fcrossjumping")
#pragma GCC optimize("-fthread-jumps")
#pragma GCC optimize("-funroll-loops")
#pragma GCC optimize("-fwhole-program")
#pragma GCC optimize("-freorder-blocks")
#pragma GCC optimize("-fschedule-insns")
#pragma GCC optimize("inline-functions")
#pragma GCC optimize("-ftree-tail-merge")
#pragma GCC optimize("-fschedule-insns2")
#pragma GCC optimize("-fstrict-aliasing")
#pragma GCC optimize("-fstrict-overflow")
#pragma GCC optimize("-falign-functions")
#pragma GCC optimize("-fcse-skip-blocks")
#pragma GCC optimize("-fcse-follow-jumps")
#pragma GCC optimize("-fsched-interblock")
#pragma GCC optimize("-fpartial-inlining")
#pragma GCC optimize("no-stack-protector")
#pragma GCC optimize("-freorder-functions")
#pragma GCC optimize("-findirect-inlining")
#pragma GCC optimize("-fhoist-adjacent-loads")
#pragma GCC optimize("-frerun-cse-after-loop")
#pragma GCC optimize("inline-small-functions")
#pragma GCC optimize("-finline-small-functions")
#pragma GCC optimize("-ftree-switch-conversion")
#pragma GCC optimize("-foptimize-sibling-calls")
#pragma GCC optimize("-fexpensive-optimizations")
#pragma GCC optimize("-funsafe-loop-optimizations")
#pragma GCC optimize("inline-functions-called-once")
#pragma GCC optimize("-fdelete-null-pointer-checks")
#include<bits/stdc++.h>
using namespace std;
#define ull unsigned long long
const int N=3050;
ull f[N];
int m;
const ull base=7;
ull hhash[N],fac[N];
const unsigned long long mod=1e9+7;
const unsigned long long P=9876553+10000;
inline int Add(int x,int y,int M=mod){return (x+y)%M;}
inline int Mul(int x,int y,int M=mod){return 1ll*x*y%M;}
inline int Max(int x,int y){return x>y?x:y;}
inline int Min(int x,int y){return x<y?x:y;}
char s[N];
inline ull Get(int l,int r){
	if(l>r)return 0;
	ull res=hhash[r]-hhash[l-1]*fac[r-l+1];
	return res;
}
inline bool check(int a,int b,int c,int d){
	if(s[a]=='0'&&s[b]=='0'&&s[c]=='1'&&s[d]=='1')return false;
	if(s[a]=='0'&&s[b]=='1'&&s[c]=='0'&&s[d]=='1')return false;
	if(s[a]=='1'&&s[b]=='1'&&s[c]=='1'&&s[d]=='0')return false;
	if(s[a]=='1'&&s[b]=='1'&&s[c]=='1'&&s[d]=='1')return false;
	return true;
}
typedef pair<unsigned long long,unsigned long long> pr;
#define fi first
#define se second
#define mk make_pair
struct B{
	vector<pr>h[P+10];
	void Insert(unsigned long long x,int val){
		int pos=x%P;
		for(auto v:h[pos]){if(v.fi==x)return;}
		h[pos].push_back(mk(x,val));
	}
	int operator[](const unsigned long long x){
		int pos=x%P;
		for(auto v:h[pos]){if(v.fi==x)return v.se;}
		return 0;
	}
}viss;
int a[N];
inline void write(long long x){
	if(x>9)write(x/10);
	putchar(x%10+'0');
}
int main(){
// 	freopen("in.txt","r",stdin);
	cin>>m;
	fac[0]=1;
	for(int i=1;i<=m;++i)fac[i]=fac[i-1]*base;
	for(int i=1;i<=m;++i)cin>>s[i];
	for(int i=1;i<=m;++i)a[i]=s[i]-'0'+1;
	hhash[0]=0;
	for(int i=1;i<=m;++i)hhash[i]=hhash[i-1]*base+a[i]+1;
	viss.Insert(0,1);
	long long ans=0;
	for(int i=1;i<=m;++i){
		for(int j=1;j<=i;++j){
			if(viss[Get(j,i)])continue;
			if(i>=j)f[j]=Add(f[j],viss[Get(j,i-1)]);
			if(i-1>=j)f[j]=Add(f[j],viss[Get(j,i-2)]);
			if(i-2>=j)f[j]=Add(f[j],viss[Get(j,i-3)]);
			if(i-3>=j&&check(i-3,i-2,i-1,i))f[j]=Add(f[j],viss[Get(j,i-4)]);
			ans=Add(ans,f[j]);viss.Insert(Get(j,i),f[j]);
		}
		for(int j=1;j<=i;++j)f[j]=0;
		write(ans);putchar('\n');
	}
	return 0;
}
posted @ 2021-10-03 21:56  Refined_heart  阅读(54)  评论(0编辑  收藏  举报