1. 程式人生 > 其它 >F2. Promising String (hard version)_BIT正序對+離散化+同餘分組

F2. Promising String (hard version)_BIT正序對+離散化+同餘分組

F2. Promising String (hard version)_BIT正序對+離散化+同餘分組

題目大意:

給一串由+-構成的序列,兩個-可以合併成一個+。一個串+-數量相等就稱其為好串,若一個串可以通過若干次合併變成好串那麼我們稱其為P串。現在給定一個串,問其中有多少的子串是P串。

思路和程式碼:

首先,一個子串的'-'的數量num0和'+'的數量num1之差為三的倍數即可(num0>=num1)。

考慮維護f陣列,fi表示[1,i]區間中num0和num1的差值。對於區間[l,r],只要滿足以下條件即可對答案產生貢獻

1)f[r]>=f[l-1]

2)(f[r] - f[l - 1]) % 3 == 0

對於條件2,我們變化一下式子可得:

(f[r] % 3 - f[l - 1] % 3) % 3 == 0

也就是說f[r] % 3要和 f[l - 1] % 3相等。於是我們可以對其模3,對同餘的進行分組。然後對012三種餘數維護一個“正序數”即可。

當然,f陣列會出現負數,但是BIT只能維護正數,所以我們可以對f陣列進行離散化

int n , m , k ;

void add(int x , int val , vct<ll> &tr){
	while(x <= n + 2){
		tr[x] += val ;
		x += (x & -x) ;
	}
}

ll query(int x , vct<ll> &tr){
	ll res = 0 ;
	while(x){
		res += tr[x] ;
		x -= (x & -x) ;
	}
	return res ;
}

int getid(int x , vct<ll> &d){
	return lower_bound(all(d) , x) - d.begin() + 1 ;
}

void solve(){
	string s ; cin >> n >> s ;
	
	vct<ll> f(n + 1 , 0) ;
	rep(i , 1 , n) f[i] = f[i - 1] + (s[i - 1] == '-' ? 1 : -1) ;
	
	vct<ll> d(1 , 0) ;
	rep(i , 1 , n) d.pb(f[i]) ;
	sort(all(d)) ;
	
	d.erase(unique(all(d)) , d.end()) ;
	
	vct<vct<ll> > tr(3 , vct<ll> (n + 2 , 0)) ;

	ll ans = 0 ;
	rep(i , 0 , n){
		int p = getid(f[i] , d) ;
		ans += query(p , tr[p % 3]) ;
		add(p , 1 , tr[p % 3]) ;
		
	}
	cout << ans << "\n" ;
	
}//code_by_tyrii 

小結: