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 &tr){
while(x <= n + 2){
tr[x] += val ;
x += (x & -x) ;
}
}
ll query(int x , vct &tr){
ll res = 0 ;
while(x){
res += tr[x] ;
x -= (x & -x) ;
}
return res ;
}
int getid(int x , vct &d){
return lower_bound(all(d) , x) - d.begin() + 1 ;
}
void solve(){
string s ; cin >> n >> s ;
vct f(n + 1 , 0) ;
rep(i , 1 , n) f[i] = f[i - 1] + (s[i - 1] == '-' ? 1 : -1) ;
vct d(1 , 0) ;
rep(i , 1 , n) d.pb(f[i]) ;
sort(all(d)) ;
d.erase(unique(all(d)) , d.end()) ;
vct > tr(3 , vct (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
小结: