Loading

题解—简单的区间

和昨天\(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 ; 
}
posted @ 2021-07-13 06:01  Soresen  阅读(45)  评论(0)    收藏  举报