【題解】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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章