11.3 欢乐爆零赛 知识总结 (Hanoi Rank Tree )

T1

这里写图片描述

hanoi 解题思路:

对于这道题,我们已知的是当 M = 2 时,这就是我们已知的【汉诺塔问题】。那么我们的思路就可以是用解决汉诺塔问题的思路来解决这道题。

这里写图片描述

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

# define Name "hanoi"
# define LL long long 

LL dp [70] [70] ;

int main () {
    freopen ( Name ".in" , "r" , stdin ) ;
    freopen ( Name ".out" , "w" , stdout ) ;
    memset ( dp , 0x3f , sizeof dp ) ;
    int n , m ;
    scanf ( "%d%d" , & n , & m ) ;
    dp [1] [3] = 1 ;
    for ( int i = 2 ; i <= n ; ++ i ) 
        dp [i] [2] = 0 ,
        dp [i] [3] = ( 1LL << i ) - 1LL ;
    for ( int i = 3 ; i <= m ; ++ i ) 
        dp [1] [i] = 1 ; 
    for ( int i = 2 ; i <= n ; ++ i ) 
        for ( int j = 4 ; j <= m ; ++ j )
            for ( int r = 1 ; r < i ; ++ r )  
            dp [i] [j] = min ( dp [i] [j] , dp [ i - r ] [j] * 2 + dp [r] [ j - 1 ] ) ;
    printf ( "%lld" , dp [n] [m] ) ; 
    return 0 ; 
}

T2

这里写图片描述

这里写图片描述

# include <vector>
# include <cstdio>
# include <cstring>
# include <iostream>
# include <algorithm>
# define LL long long
# define Name "rank" 

using namespace std;

const int N = 2e5 + 10 ;

char ch [N] ;

struct P {
    int len , rk ;
    bool operator < ( const P & x ) const {
        return rk < x.rk ;
    }
} a [N] ;

int rk [N] ;
int n ;

int id ( int len ) {
    return n - len + 1 ;
}
int main () {
    freopen ( Name ".in" , "r" , stdin ) ;
    freopen ( Name ".out" , "w" , stdout ) ;
    memset ( ch , '\0' , sizeof ch ) ;
    scanf ( "%d" , & n ) ;
    for ( int i = 1 ; i <= n ; ++ i ) {
        scanf ( "%d" , & a [i].rk ) ;
        rk [ n - i + 1 ] = a [i].rk ;
        a [i].len = n - i + 1  ;
    }
    sort ( a + 1 , a + 1 + n ) ;
    for ( int i = 1 ; i < n ; ++ i ) {
        int l1 = a [i].len - 1 ;
        int l2 = a [ i + 1 ].len - 1 ;
        if ( rk [l1] > rk [l2] ) {
            if ( ch [ id ( l1 + 1 ) ] == '\0' ) 
                ch [ id ( l1 + 1 ) ] = 'a' ;
            if ( ch [ id ( l2 + 1 ) ] == '\0' ) 
                ch [ id ( l2 + 1 ) ] = ch [ id ( l1 + 1 ) ] + 1 ; 
            if ( ch [ id ( l2 + 1 ) ] > ch [ id ( l1 + 1 ) ] + 1 ) {
                printf ( "-1" ) ;
                return 0 ;
            } 
        } else {
            if ( ch [ id ( l1 + 1 ) ] == '\0' ) 
                ch [ id ( l1 + 1 ) ] = 'a' ;
            if ( ch [ id ( l2 + 1 ) ] == '\0' ) 
                ch [ id ( l2 + 1 ) ] = ch [ id ( l1 + 1 ) ] ; 
            if ( ch [ id ( l2 + 1 ) ] != ch [ id ( l1 + 1 ) ] ) {
                printf ( "-1" ) ;
                return 0 ;
            } 
        }  
    }
    for ( int i = 1 ; i <= n ; ++ i ) {
        if ( ch [i] < 'a' || ch [i] > 'z' ) {
            printf ( "-1" ) ;
            return  0 ;
        }
    }
    for ( int i = 1 ; i <= n ; ++ i ) 
        printf ( "%c" , ch [i] ) ;
    return 0 ;
}

T3

这里写图片描述

期望概率神题:

这里写图片描述


# include <vector>
# include <cstdio>
# include <cstring>
# include <iostream>
# include <algorithm>
# define LL long long
# define Name ""
using namespace std ;

const int N = 2e5 + 10 ;
const int P = 17 ;

const LL Mod = 1e9 + 7 ;

vector <int> G [N] ;

int sz [N] , dep [N] , fa [N] [20] ;
int n , q ;

LL f [N] , g [N] , pw [30] ;

int LCA ( int u , int v ) {
    if ( dep [u] < dep [v] ) swap ( u , v ) ;
    int t = dep [u] - dep [v] ;
    for ( int i = 0 ; pw [i] <= t ; ++ i ) 
        if ( pw [i] & t ) u = fa [u] [i] ;
    for ( int i = P ; i >= 0 ; -- i ) {
        if ( fa [u] [i] != fa [v] [i] ) {
            u = fa [u] [i] ;
            v = fa [v] [i] ;
        }
    }
    if ( u == v ) return u ;
    return fa [u] [0] ;
}


void dfs ( int u , int fat ) {
    fa [u] [0] = fat ;
    for ( int i = 1 ; i <= P ; ++ i )
        fa [u] [i] = fa [ fa [u] [ i - 1 ] ] [ i - 1 ] ; 
    sz [u] = 1 ;
    for ( int i = 0 ; i < G [u].size () ; ++ i ) {
        int v = G [u] [i] ;
        if ( v == fat ) continue ;
        dep [v] = dep [u] + 1 ;
        dfs ( v , u ) ;
        sz [u] += sz [v] ;
    }
}

void dfs_da ( int u , int fat ) {
    for ( int i = 0 ; i < G [u].size () ; ++ i ){
        int v = G [u] [i] ;
        if ( v == fat ) continue ;
        f [v] = ( LL ) ( f [u] + 2LL * ( n - sz [v] ) - 1LL ) % Mod ;
        g [v] = ( LL ) ( g [u] + 2LL * sz [v] - 1LL ) % Mod;
        dfs_da ( v , u ) ;
    }
}

int main () {
    freopen ("tree.in", "r", stdin);
    freopen ("tree.out", "w", stdout);
    pw [0] = 1 ;
    for ( int i = 1 ; i <= P ; ++ i ) pw [i] = pw [ i - 1 ] * 2 ;
    scanf ( "%d%d" , & n , & q ) ;
    for ( int i = 1 ; i < n ; ++ i ) {
        int x , y ;
        scanf ( "%d%d" , & x , & y ) ;
        G [x].push_back ( y ) ;
        G [y].push_back ( x ) ;
    }
    dfs ( 1 , 1 ) ;
    dfs_da ( 1 , 1 ) ;
    while ( q -- ) {
        int u , v ;
        scanf ( "%d%d" , & u , & v ) ;
        int x = LCA ( u , v ) ;
//      printf ( ">%d %d %d \n" , u , v , x ) ;
        printf ( "%lld\n" , ( ( f [v] - f [x] + g [u] - g [x] ) % Mod + Mod ) % Mod ) ;
    }
    return 0 ;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值