说在前面
辣鸡常数
毁me青春
费me钱财
题目
BZOJ3714传送门
看题可戳传送门
解法
可能刚开始接触这类题的时候,感觉很妙妙,所以为了不点破,并没有在标题上写出解法
如果是第一次见这种题,可以多想一想,然后再往下翻
然而见多了都是套路...
嗯好,开始说正事=w=
把题目用自己的语言说出来,是这样的:一串序列,每个位置有0/1两种取值,用最小的代价确定每个位置的取值
很容易想到的是,如果我们选取了两个区间
[l,r]
[
l
,
r
]
和
[l+1,r−1]
[
l
+
1
,
r
−
1
]
,那么我们就可以知道
l
l
和 的关系
如果可以找出一些关系链,并询问几个单点的值,那么根据这些关系链,就可以推断出所有的值。
这乍一看像是个最小生成树
但是,如果这样去找关系的话,发现能够形成关系链的选法太多了,我们必须换一种思考方式,来避免这个问题
询问一个区间,就相当于知道了它们的异或和,就相当于是知道了 sum[r]⊕sum[l−1] s u m [ r ] ⊕ s u m [ l − 1 ] ( sum s u m 表示异或前缀和)。如果能够知道全部的 sum s u m ,那么整个序列的值也就知道了。于是它确实是个最小生成树……
下面是卡常失败的代码
(最小生成树me写的是Boruvka算法)
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std ;
int N ;
struct Path{
short fr , to ;
int val ;
} cho[2005] ;
struct Data{
Path p[2002005] ; //C( 1001 , 2 ) = 20001000 ;
int pcnt ;
inline void push( const Path &A ) { p[++pcnt] = A ; }
void clear(){ pcnt = 0 ; }
} P ;
struct Union_Set{
int fa[2005] , siz[2005] ;
void init(){
for( int i = 0 ; i <= N ; i ++ )
fa[i] = i , siz[i] = 1 ;
}
int find( int x ){
if( fa[x] == x ) return x ;
return fa[x] = find( fa[x] ) ;
}
bool Union( int a , int b ){
int Fa = find( a ) , Fb = find( b ) ;
if( Fa == Fb ) return false ;
if( siz[Fa] < siz[Fb] ) swap( Fa , Fb ) ;
siz[Fa] += siz[Fb] , fa[Fb] = Fa ;
return true ;
}
} U ;
void solve(){
U.init() ;
long long ans = 0 ;
Data *a = &P ;
for( register int cnt = N , i ; cnt ; ){
Path t ;
for( i = 0 ; i <= N ; i ++ ) cho[i].val = 0x3f3f3f3f ;
for( i = 1 ; i <= a->pcnt ; i ++ ){
t = a->p[i] ;
t.fr = U.find( t.fr ) , t.to = U.find( t.to ) ;
if( t.fr == t.to ) continue ;
if( cho[ t.fr ].val > t.val ) cho[ t.fr ] = t ;
if( cho[ t.to ].val > t.val ) cho[ t.to ] = t ;
}
for( i = 0 ; i <= N ; i ++ )
if( cho[i].val != 0x3f3f3f3f && U.Union( cho[i].fr , cho[i].to ) )
ans += cho[i].val , cnt -- ;
} printf( "%lld" , ans ) ;
}
inline int read_(){
int rt = 0 ;
char ch = getchar() ;
while( ch < '0' || ch > '9' ) ch = getchar() ;
while( ch >='0' && ch <='9' ) rt = ( rt << 1 ) + ( rt << 3 ) + ch - '0' , ch = getchar() ;
return rt ;
}
int main(){
scanf( "%d" , &N ) ;
for( short i = 0 ; i < N ; i ++ )
for( short j = i + 1 ; j <= N ; j ++ )
P.push( ( Path ){ i , j , read_() } ) ;
solve() ;
}