NOIP2024模擬賽13:拆開未來

superl61發表於2024-06-22

NOIP2024模擬賽13:拆開未來

C-重複

  • 一句話題意:給定字串 \(S\), 問 \(S\) 的所有子串共有多少種“好的拆分方案”。對於一個字串 \(S\), 一個劃分是好的當且僅當能把 \(S\) 劃分成 6 個非空子串 \(a,b,c,d,e\), 滿足 \(a=b=e, \ c=f\) (一個字串可能有多種劃分方式)

  • 標籤:字首和,思維,雜湊表(雜湊)

  • 簡化一下就是要滿足 \(AABCAB\).

  • 60分的暴力是對每一個區間列舉開頭的 \(A\) 和結尾的 \(B\). (P.S.模數設 \(998244353\) 會被卡!!!)

    const int N=5005;
    const ll P=131;
    ull h[N],p[N];
    char s[N];
    int n; ll ans=0;
    ull get(int l,int r){ return h[r]-h[l-1]*p[r-l+1]; }
    void solve(int l,int r){
    	int len=r-l+1;
    	F(i,1,len/3) for(int j=1;j<=len/2 && 3*i+2*j<len;++j){
    			ull A=get(l,l+i-1),B=get(l+i,l+2*i-1),C=get(l+2*i,l+2*i+j-1),E=get(r-i-j+1,r-j),F=get(r-j+1,r); 
    			if(A == B && B == E && C == F) ++ans;
    		}
    }
    signed main(){
    	freopen("c.in","r",stdin); freopen("c.out","w",stdout);
    	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    	cin>>(s+1); n=strlen(s+1); p[0]=1;
    	F(i,1,n) h[i]=h[i-1]*P+s[i]-'0',p[i]=p[i-1]*P;
    	F(l,1,n) F(r,l+5,n) solve(l,r);
    	cout<<ans;
    	return 0;
    }
    
  • 但正如鄧老師所說,這種拆分方式是“不平衡的”,雖然我們可以用 \(O(1)\) 的時間去檢查剩下的位置,但我們卻需要花 \(O(N^2)\) 的時間列舉所有的首尾情況。

  • 所以正解我們選擇列舉 \(AB\). 列舉 \(A\) 的左端點 \(i\)\(B\) 的右端點 \(j\).

  • 對於 \(AA\), 在固定 \(i\) 的情況下可以用字首和處理所有貢獻。

  • 對於 \(AB\) 和後面那個 \(AB\) 的匹配, 把所有已經掃到過的 \(AB\) 存進一個雜湊表並統計其個數(\(unorderedmap\) 會 T掉)

  • 兩者的貢獻相乘即是單次的總貢獻。

  • 注意迴圈的初末條件,\(C\) 不為空(詳見程式碼)

#include<bits/stdc++.h>
#define F(i,l,r) for(register int i(l);i<=r;++i)
using namespace std;
using ll = long long;
using ull = unsigned long long;
const int N=5005;
const ll P=131;
ull h[N],p[N];
char s[N];
int n; ll ans=0;
ull get(int l,int r){ return h[r]-h[l-1]*p[r-l+1]; }
void solve(int l,int r){
	int len=r-l+1;
	F(i,1,len/3) for(int j=1;j<=len/2 && 3*i+2*j<len;++j){
			ull A=get(l,l+i-1),B=get(l+i,l+2*i-1),C=get(l+2*i,l+2*i+j-1),E=get(r-i-j+1,r-j),F=get(r-j+1,r); 
			if(A == B && B == E && C == F) ++ans;
		}
}
signed main(){
	freopen("c.in","r",stdin); freopen("c.out","w",stdout);
	ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
	cin>>(s+1); n=strlen(s+1); p[0]=1;
	F(i,1,n) h[i]=h[i-1]*P+s[i]-'0',p[i]=p[i-1]*P;
	F(l,1,n) F(r,l+5,n) solve(l,r);
	cout<<ans;
	return 0;
}