[BZOJ5335]-[TJOI2018]智力競賽-二分答案+可重路徑覆蓋

說在前面

md筆記本鍵盤真難用…
到了林蔭校區了qwq,感覺很棒!


題目

BZOJ5335傳送門
看題可戳傳送門


解法

me覺得這個題面描述十分不清真
題意就是讓求可重最小鏈覆蓋,但是題目上並沒有說有沒有環,所以正常寫法就是先tarjan,然後跑一遍floyd處理連通性,最後二分答案check

然而me覺得出題人不可能強行tarjan,於是把LOJ的數據全部下載下來check了一遍,發現全是DAG= =???

這就很有意思了…


下面是自帶大常數的代碼

me也不知道爲啥,反正跑的慢

#include <cstring>
#include <algorithm>
using namespace std ;

int N , M , head[505] , tp ;
bool acce[505][505] ;
struct Data{
    int id , val ;
    bool operator < ( const Data &A ) const {
        return val < A.val ;
    }
} d[505] ;
struct Path{
    int pre , to ;
} p[250005] ;

void In( int t1 , int t2 ){
    p[++tp] = ( Path ){ head[t1] , t2 } ; head[t1] = tp ;
}

void preWork(){
    sort( d + 1 , d + M + 1 ) ;
    for( int k = 1 ; k <= M ; k ++ )
        for( int i = 1 ; i <= M ; i ++ ) if( i != k )
            for( int j = 1 ; j <= M ; j ++ ) if( j != k && j != i )
                if( !acce[i][j] ) acce[i][j] = ( acce[i][k] & acce[k][j] ) ;
    for( int i = 1 ; i <= M ; i ++ )
        for( int j = 1 ; j <= M ; j ++ )
            if( i != j && acce[i][j] ) In( i , j ) ;
}

int mat[505] ;
bool vis[505] , ban[505] ;
bool match( int u ){
    for( int i = head[u] ; i ; i = p[i].pre ){
        int v = p[i].to ;
        if( vis[v] || ban[v] ) continue ;
        vis[v] = true ;
        if( !mat[v] || match( mat[v] ) ){
            mat[v] = u ;
            return true ;
        }
    } return false ;
}

bool check( int mid ){
    int cnt = 0 ;
    memset( ban , 0 , sizeof( ban ) ) ;
    memset( mat , 0 , sizeof( mat ) ) ;
    for( int i = mid + 1 ; i <= M ; i ++ ) ban[ d[i].id ] = true ;
    for( int i = 1 ; i <= M ; i ++ ){
        if( ban[i] ) continue ;
        memset( vis , 0 , sizeof( vis ) ) ;
        cnt += match( i ) ;
    } return mid - cnt <= N + 1 ;
}

void solve(){
    int lf = 1 , rg = M - 1 , mid , ans ;
    if( check( M ) ) puts( "AK" ) , exit( 0 ) ;
    while( lf <= rg ){
        mid = ( lf + rg ) >> 1 ;
        if( check( mid ) )
            ans = mid , lf = mid + 1 ;
        else rg = mid - 1 ;
    } printf( "%d\n" , d[ans+1].val ) ;
}

int main(){
    scanf( "%d%d" , &N , &M ) ;
    for( int i = 1 , son ; i <= M ; i ++ ){
        scanf( "%d" , &d[i].val ) , d[i].id = i ;
        scanf( "%d" , &son ) ;
        for( int j = 1 , v ; j <= son ; j ++ )
            scanf( "%d" , &v ) , acce[i][v] = true ;
    } preWork() ; solve() ;
}

發佈了268 篇原創文章 · 獲贊 29 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章