题解—简单的区间
和昨天\(T3\)一样,考场上想到了边界的处理,但是忘了取模了,导致昨天\(T1\)应该爆的\(0\)爆到这题上了,唉,用过的\(rp\),早晚要还的。
这个东西我用权值线段树维护的,但是貌似\(vector\)加二分也可以胜任这个操作。
主要就是元素只有\(N\)个,保证不爆空间什么都好说。
区间还是暴力搜小的那个,因为所有区间只能包含或者独立,不能相交,所以复杂度是对的。
#include <cstdio>
#include <algorithm>
#include <cstring>
#define R register int
#define int long
#define scanf Ruusupuu = scanf
#define printf Ruusupuu = printf
int Ruusupuu ;
using namespace std ;
typedef long long L ;
typedef long double D ;
typedef pair< int , int > PI ;
const int N = 3e5 + 10 ;
const int M = 1e6 + 10 ;
inline int read(){
int w = 0 ; bool fg = 0 ; char ch = getchar() ;
while( ch < '0' || ch > '9' ) fg |= ( ch == '-' ) , ch = getchar() ;
while( ch >= '0' && ch <= '9' ) w = ( w << 1 ) + ( w << 3 ) + ( ch - '0' ) , ch = getchar() ;
return fg ? -w : w ;
}
int n , k , a [N] , s [N] , t [N] , root [M] , st [N] , top , lsi [N] , rsi [N] ;
inline int J( int a , int b ){ return ( ( a + b ) % k ) ; }
L ans ;
int l [N << 5] , r [N << 5] , ls [N << 5] , rs [N << 5] , dt [N << 5] , gnt ;
#define ud( x ) dt [x] = dt [ls [x]] + dt [rs [x]]
void ins( int &x , int ll , int rr , int pos , int dlt ){
if( !x ) x = ++ gnt , l [x] = ll , r [x] = rr ;
if( ll == rr ){ dt [x] += dlt ; return ; }
int mid = ( ll + rr ) >> 1 ;
if( pos <= mid ) ins( ls [x] , ll , mid , pos , dlt ) ;
else ins( rs [x] , mid + 1 , rr , pos , dlt ) ;
ud( x ) ;
}
int ask( int x , int ll , int rr ){
// printf( "ASk%ld %ld %ld %ld %ld\n" , x , l [x] , r [x] , ll , rr ) ;
if( rr < ll || !x ) return 0 ;
if( l [x] >= ll && r [x] <= rr ) return dt [x] ;
int mid = ( l [x] + r [x] ) >> 1 , ans = 0 ;
if( ll <= mid ) ans += ask( ls [x] , ll , rr ) ;
if( rr > mid ) ans += ask( rs [x] , ll , rr ) ;
return ans ;
}
void sc(){
n = read() , k = read() ;
ins( root [0] , 0 , n , 0 , 1 ) ;
for( R i = 1 ; i <= n ; i ++ ){
a [i] = read() , s [i] = J( s [i - 1] , a [i] ) ;
// printf( "%ld %ld\n" , a [i] , s [i] ) ;
ins( root [s [i]] , 0 , n , i , 1 ) ;
}// for( R i = 1 ; i <= gnt ; i ++ ) printf( "%ld %ld %ld %ld %ld %ld\n" , i , l [i] , r [i] , ls [i] , rs [i] , dt [i] ) ;
// for( R i = 0 ; i < k ; i ++ ) printf( "RT%ld\n" , root [i] ) ;
}
inline L cal( int l , int r , int v ){
L ans = 0 ;
int len1 = v - l + 1 , len2 = r - v + 1 ;
// printf( "%ld %ld\n" , len1 , len2 ) ;
if( len1 <= len2 ){
for( R i = l ; i < v ; i ++ ){
int x = J( s [i - 1] , a [v] ) ;
ans += ask( root [x] , v , r ) ;
} ans += ask( root [s [v]] , v + 1 , r ) ;
}
else{
for( R i = v + 1 ; i <= r ; i ++ ){
int x = ( s [i] - a [v] + k ) % k ;
ans += ask( root [x] , l - 1 , v - 1 ) ;
}// printf( "R%ld %ld %ld\n" , s [v - 1] , l - 1 , v - 2 ) ,
ans += ask( root [s [v - 1]] , l - 1 , v - 2 ) ;
}
// printf( "%lld\n" , ans ) ;
return ans ;
}
void work(){
a [0] = (int) 1e9 + 10 , a [n + 1] = (int) 1e9 + 10 ;
for( R i = 0 ; i <= n ; i ++ ){
while( top >= 1 && a [st [top]] < a [i] ) top -- ;
lsi [i] = st [top] + 1 , st [++ top] = i ;
}
for( R i = n + 1 , top = 0 ; i >= 1 ; i -- ){
while( top >= 1 && a [st [top]] <= a [i] ) top -- ;
rsi [i] = st [top] - 1 , st [++ top] = i ;
}
for( R i = 1 ; i <= n ; i ++ ) a [i] %= k ;
for( R i = 1 ; i <= n ; i ++ ) //printf( "LR%ld %ld\n" , lsi [i] , rsi [i] ) ,
ans += cal( lsi [i] , rsi [i] , i ) ;
printf( "%lld\n" , ans ) ;
}
signed main(){
sc() ;
work() ;
return 0 ;
}
$The \ light \ has \ betrayed \ me$

浙公网安备 33010602011771号