1. 程式人生 > 其它 >ICPC_2022_Xian&&Guiling 賽後補題

ICPC_2022_Xian&&Guiling 賽後補題

Find Maximum

一個很重要的性質就是f(x)表示的是x在三進位制下的位數加上各位上的數字之和 這個觀察f(x)的題面也很容易看出來

所以只需要儘量讓x在三進位制下2最多即可 直接列舉貪心就行 

#include<bits/stdc++.h>
using namespace std ;
#define maxn 400100
#define int long long
int read(){
    int ans = 0 , f = 1 ; char ch = getchar() ;
    while ( !isdigit(ch) ){ if( ch == '-' ) f = -1
; ch = getchar() ; } while ( isdigit(ch) ) ans = (ans * 10) + (ch ^ '0') , ch = getchar() ; return ans * f ; } int l , r , t ; int f(int x){ if(x == 0){ return 1 ; } if(x > 0 && x % 3 == 0) return f(x / 3) + 1 ; return f(x - 1) + 1 ; } void solve(){ vector
<int> R ; l = read() , r = read() ; int ans = max(f(l) , f(r)) ; int temp = r ; while(temp){ R.push_back(temp % 3) ; temp /= 3 ; } int si = R.size() ; reverse(R.begin() , R.end()); for(int i = 0 ; i < si ; i++){ if(R[i] == 0){
continue ; } int sum = 0 ; for(int j = 0 ; j < i ; j++) sum = sum * 3 + R[j] ; sum = sum * 3 + R[i] - 1 ; for(int j = i + 1 ; j < si ; j++) sum = sum * 3 + 2 ; if(sum >= l) ans = max(ans , f(sum)) ; } printf("%lld\n" , ans) ; } signed main(){ // freopen("test.in" , "r" , stdin) ; // freopen("test.out" , "w" , stdout) ; t = read() ; while(t--){ solve() ; } return 0 ; }

L題Tree

首先我們通過對樣例的模擬 可以發現一些性質 發現我們現在每次有兩種操作 要麼是吧最底層的葉子全部砍掉 要麼是用鏈去覆蓋 

本題暫未找到嚴謹的貪心證明 目前我發現先取葉子再取鏈和先取鏈再取葉子兩種貪心方式都是正確的 (先留個坑吧

#include<bits/stdc++.h>
using namespace std ;
#define maxn 2000100
#define int long long
int read(){
    int ans = 0 , f = 1 ; char ch = getchar() ;
    while ( !isdigit(ch) ){ if( ch == '-' ) f = -1 ; ch = getchar() ; }
    while ( isdigit(ch) ) ans = (ans * 10) + (ch ^ '0') , ch = getchar() ;
    return ans * f ;
}
int to[maxn] , nxt[maxn] , head[maxn] , cnt ; 
void add(int u , int v){
    to[++cnt] = v , nxt[cnt] = head[u] ; head[u] = cnt ; 
}
int num[maxn] , f[maxn]; 
int t , n ; 
void dfs(int u , int fa){
    f[u] = 1 ;  
    for(int i = head[u] ; i ; i = nxt[i]){
        int v = to[i] ; 
        if(v == fa) continue ; 
        dfs(v , u) ; 
        f[u] = max(f[u] , f[v] + 1) ; 
    }
    return ; 
}
void solve(){
    n = read() ;
    memset(f , 0 , sizeof(int) * (n + 10)) ; memset(num , 0 , sizeof(int) * (n + 10)) ; 
    cnt = 0  ; //memset(to , 0 , sizeof(to)) ; 
    memset(head , 0 , sizeof(int) * (n * 2 + 10)) ; //memset(nxt , 0 , sizeof(nxt)) ; 
    int ans = 999999999 ; 
//    n = read() ; 
    for(int i = 2 ; i <= n ; i++){
        int u = read() , v = i ; 
        add(u , v) ; add(v , u) ; 
    }
    for(int i = 1 ; i <= n ; i++)
        if(f[i] == 0) dfs(i , i) ;  
    for(int i = 1 ; i <= n ; i++)
        num[f[i]]++ ;// printf("f[%lld] :%lld \n" , i , f[i]); 
    for(int i = 1 ; i <= n ; i++)
        ans = min(ans , num[i] + i - 1) ;// printf("num[%lld] : %lld \n" , i , num[i] + i - 1); 
    printf("%lld\n" , ans) ; 
}
signed main(){
//    freopen("test.in" , "r" , stdin) ;
//    freopen("test.out" , "w" , stdout) ;
    t = read() ; 
    while(t--){
        solve() ; 
    }
    return 0 ;
}

BCells Coloring(待補)

Group Homework

換跟dp 

換跟的步驟其實就是先刪掉v節點對u節點的貢獻 然後再把u節點的貢獻插入v節點即可 

對於每個點 我們可以開一個multiset 這樣再計算轉移的時候的最大值會方便很多

需要注意的是撤銷貢獻和計算貢獻的順序 搞清楚先後

#include<bits/stdc++.h>
using namespace std ;
#define maxn 400100
#define int long long
int read(){
    int ans = 0 , f = 1 ; char ch = getchar() ;
    while ( !isdigit(ch) ){ if( ch == '-' ) f = -1 ; ch = getchar() ; }
    while ( isdigit(ch) ) ans = (ans * 10) + (ch ^ '0') , ch = getchar() ;
    return ans * f ;
}
int ans = 0 ;  
vector<int> G[maxn] ;
int a[maxn] ; 
int n ; 
struct node{
    multiset<int> st ; 
    void add(int x){
        st.insert(x) ; 
    }
    void del(int x){
        st.erase(st.find(x));
    }
    int operator [] (int id)const {
        auto it = st.end() ; 
        for(int i = 0 ; i <= id ; i++) it-- ; 
        return *it ; 
    }
}mx_line[maxn] , mx_sub[maxn];
void dfs(int u , int fa){
    for(int i = 1 ; i <= 3 ; i++){
        mx_line[u].add(0) ; 
        mx_line[u].add(0) ; 
        mx_sub[u].add(0) ;  
    }
    for(int i = 0 ; i < G[u].size() ; i++){
        int v = G[u][i] ; 
        if(v == fa) continue ; 
        dfs(v,u) ; 
        mx_line[u].add(mx_line[v][0] + a[v]) ; 
        mx_sub[u].add(mx_sub[v][0]) ; 
    }
    mx_sub[u].add(mx_line[u][0] + a[u] + mx_line[u][1]) ; 
} 
void dfs1(int u , int fa){
//    ans = max(ans , mx_line[u][0] + mx_line[u][1] + mx_line[u][2] + mx_line[u][3]) ; 
    for(int i = 0 ; i < G[u].size() ; i++){
        int v = G[u][i] ; 
        if(v == fa) continue ; 
        int del_sub1 = mx_line[u][0] + a[u] + mx_line[u][1] ; 
        int del_sub2 = mx_sub[v][0] ; 
        int del_line = mx_line[v][0] + a[v] ; 
        mx_sub[u].del(del_sub1) ; 
        mx_sub[u].del(del_sub2) ; 
        mx_line[u].del(del_line) ; 
        mx_sub[u].add(mx_line[u][0] + a[u] + mx_line[u][1]) ; 
        ans = max(ans , mx_sub[u][0] + mx_sub[v][0]) ; 
        mx_sub[v].del(mx_line[v][0] + mx_line[v][1] + a[v]) ; 
        mx_line[v].add(mx_line[u][0] + a[u]) ;
        mx_sub[v].add(mx_line[v][0] + mx_line[v][1] + a[v]) ;
        mx_sub[v].add(mx_sub[u][0]) ; 
        dfs1(v , u) ; 
        mx_sub[u].del(mx_line[u][0] + a[u] + mx_line[u][1]) ;
        mx_line[u].add(del_line) ; 
        mx_sub[u].add(del_sub2) ; 
        mx_sub[u].add(del_sub1) ;  
    }
}
signed main(){
//    freopen("test.in" , "r" , stdin) ;
//    freopen("test.out" , "w" , stdout) ;
    n = read() ; 
    for(int i = 1 ; i <= n ; i++){
        a[i] = read() ; 
    }
    for(int i = 1 ; i < n ; i++){
        int u = read() , v = read() ; 
        G[u].push_back(v) ; 
        G[v].push_back(u) ; 
    }
    if(n == 1){
        printf("0") ; 
        return 0 ; 
    }    
    dfs(1,0) ; 
//    ans = mx_sub[1][0] ; 
    dfs1(1,0) ; 
    printf("%lld" , ans) ; 
    return 0 ;
}