Codeforces Round #250 (Div. 2) && (Div. 1) D题

来源:互联网 发布:免费开源asp源码 手机 编辑:程序博客网 时间:2024/05/18 03:27

昨天准备报名的时候cf卡得进不去,然后恢复的时候... 没得报名了抓狂 只能悲剧的看看题

A. The Child and Homework

题意 :  题目来源于此考试口诀: “三长一短选最长,三短一长选最短。长短不一选B,参差不齐选D,实在不会选C ... ” 。 当然题目没有这么复杂,只要判断三长一短和三短一长就行了,如果没有答案,或者有多个可选答案就选C( 貌似很多人因为这个被hack了 ) 。三长一短要求比其他三个选项长一倍或以上,三短一长要求比其他三个选项短一倍或以上。

思路 : 直接模拟就可以了 ...  注意下如果有两个选项分别满足三短一长和三长一短要选C


#include <stdio.h>#include <string.h>#include <algorithm>#include <iostream>#include <string>using namespace std;string ans[4] ;int main(){    cin>>ans[0] ;    cin>>ans[1] ;    cin>>ans[2] ;    cin>>ans[3] ;    int aa = -1 ;    int cnt = 0 ;    for( int i = 0 ; i < 4 ; i ++ ) {        bool ok = true ;        for( int j = 0 ; j < 4 ; j ++ ) {            if( i == j ) continue ;            if( ( ans[i].length() - 2 ) >= ( ans[j].length() - 2 ) * 2 ) {                continue ;            }            ok = false ;        }        if( ok ) {            aa = i ; cnt ++ ;            continue ;        }        ok = true ;        for( int j = 0 ; j < 4 ; j ++ ) {            if( i == j ) continue ;            if( ( ans[i].length() - 2 ) * 2 <= ( ans[j].length() - 2 ) ) {                continue ;            }            ok = false ;        }        if( ok ) {            aa = i ; cnt ++ ;            continue ;        }    }    if( cnt == 1 ) {        printf( "%c\n" , 'A' + aa ) ;    }else{        puts( "C" ) ;    }    return 0 ;}

B. The Child and Set


题意 : 给定一个sum和limit , 你需要从1~limit中选择几个不同的数字组成一个集合,使这个集合的所有数字的lowbit的和为sum,不能选出来则输出-1

思路 : 把所有的数字按照lowbit排序,然后每次都贪心选择最大的那个就行了


#include <stdio.h>#include <string.h>#include <algorithm>#include <vector>using namespace std;vector<int> ans[100005] ;vector<int> a ;int main(){    int sum , limit ;    scanf( "%d%d" , &sum , &limit ) ;    for( int i = 1 ; i <= limit ; i ++ ) {        ans[ i ^ (i & ( i - 1 )) ].push_back( i ) ;    }    for( int i = 100000 ; i >= 1 ; i -- ) {        if( ans[i].size() == 0 ) continue ;        for( int j = 0 ; j < ans[i].size() && sum >= i ; j ++ ) {            sum -= i ;            a.push_back( ans[i][j] ) ;        }    }    if( sum == 0 ) {        printf( "%d\n" , a.size() ) ;        for( int i = 0 ; i < a.size() ; i ++ ) {            printf( i == 0 ? "%d":" %d" , a[i] ) ;        }        puts( "" ) ;    }else{        puts( "-1" ) ;    }    return 0 ;}

C. The Child and Toy

题意 : 有n个点,m条无向边,每个点都有一个点权,我们需要删除掉这n个点,删除掉每个点的费用是与这个点相连的还未删除的所有点的点权和。

思路 : 我们先根据边去考虑 , 因为每条边都需要被删除 , 那么删除掉这条边的费用 , 必然是这条边的端点之一。那么如果删除掉每条边的费用都是两个端点中较小的那个费用,那么结果一定是最小的。 那么我们能不能办到这个呢 ? 只要按照点权从大到小删除,就行了。 所以求的时候只要把每条边的两个端点中的最小权值加上就行了。


#include <stdio.h>#include <string.h>#include <algorithm>using namespace std;#define MAXN 1005int val[MAXN] ;int main(){    int n , m ;    while( scanf( "%d%d" , &n , &m ) != EOF ) {        for( int i = 1 ;i <= n;  i ++ )             scanf( "%d" , &val[i] ) ;        int ans = 0 ;        for( int i = 1 ;i <= m ;i  ++ ) {            int a, b ;            scanf( "%d%d" , &a , &b ) ;            ans += min( val[a]  , val[b] ) ;        }         printf( "%d\n" , ans ) ;    }     return 0 ;}


D. The Child and Zoo

题意 : 动物园中有n景点 , 每个景点有一个权值 , f(p,q) 为从景点p到景点q的所有简单路径中,路径中经过景点权值最小值的最大值 ( 有点绕 ... ) 。要求求的是 Σ( f(p,q) ) / ( n * ( n - 1 ) )

思路 : 类似的前面做过好多了,不过之前做过的权值在边上 , 只要用并查集搞搞就行了。 如何把权值变到边上呢 ? 很显然一条的权值应该是两个端点的最小值。那么问题就变成求从景点p到景点q的所有简单路径中,路径中经过边权值最小值的最大值了。那么我们只要把边权从大到小排序,用并查集记录每个集合的顶点数,按照边权从大到小合并集合,如果两个集合之前不连通,那么从其中一个集合的点到另外一个集合的点必须要经过当前这条边,并且因为边权从大到小排序,那么这个条边就必然是从集合a的点到集合b的点所经过的路径中边权的最小值,当然后面可能也会有其他边能连通这两个集合,但现在这条边是这些边中最大的,所以我们只要在合并的时候统计下就行了。总数加上( 集合A的顶点数  +  集合B的顶点数 ) * 2 * 边权 即可


#include <stdio.h>#include <string.h>#include <algorithm>using namespace std;#define MAXN 100005int Set[MAXN] , Rank[MAXN] ;double ans ;void init( int n ){    for( int i = 1 ; i <= n ; i ++ ) {        Set[i] = i ;        Rank[i] = 1 ;    }}int val[MAXN] ;struct Edge{    int a , b , val ;}edge[MAXN] ;bool cmp( Edge a , Edge b ) {    return a.val > b.val ;}int find( int x ) {    return Set[x] == x ? Set[x] : Set[x] = find( Set[x] ) ;}void Union( int x, int y , int val ) {    int fx = find( x ) , fy = find( y ) ;    if( fx == fy ) return ;    ans += 1.0 * Rank[fx] * Rank[fy] * 2 * val ;    Set[fx] = fy ;    Rank[fy] += Rank[fx] ;}int main(){    int n , m ;    while( scanf( "%d%d" , &n ,&m ) != EOF ) {        init( n ) ;        for( int i = 1 ; i <= n ; i ++ ) {            scanf( "%d" , &val[i] ) ;        }        for( int i = 1 ; i <= m ; i ++ ) {            int u , v ;            scanf( "%d%d" , &u , &v ) ;            edge[i].a = u ;            edge[i].b = v ;            edge[i].val = min( val[u] , val[v] ) ;        }        sort( edge + 1 , edge + 1 + m , cmp ) ;        ans = 0 ;        for( int i = 1 ; i <= m ; i ++ ) {            Union( edge[i].a , edge[i].b , edge[i].val ) ;        }        printf( "%lf\n" , ans / ( 1.0 * n * ( n-1 ) ) ) ;    }    return 0 ;}

Div1. D. The Child and Sequence

题意 : 给你一个序列 , a[1] ... a[n] , 有三种操作

操作1 : 求 a[ L , R ] 的和

操作2 : 把 a[ L , R ] 的所有数字对x取模

操作3 : 把 a[k] 改成 x


思路 : 只有操作1和操作3的话,那么就是赤果果的线段树了,主要是操作2该如何更新。我的做法是维护一个最大值 , 如果某个区间的最大值小于 x , 那么这个区间就不用更新下去了, 否则就向下更新 。

#include <stdio.h>#include <string.h>#include <algorithm>using namespace std;#define lson l , m , rt << 1 #define rson m + 1 , r  , rt << 1 | 1 #define MAXN 100005__int64 sum[MAXN<<2] , Max[MAXN<<2] ;void pushup( int rt ) {sum[rt] = sum[rt<<1] + sum[rt<<1|1] ;Max[rt] = max( Max[rt<<1] , Max[rt<<1|1] ) ;}void build( int l , int r , int rt ) {int m ;if( l == r ) {scanf( "%I64d" , &sum[rt] ) ;Max[rt] = sum[rt] ;return ;}m = ( l + r  )>> 1 ;build( lson ) ;build( rson ) ;pushup( rt ) ;} __int64 query( int l,int r, int rt , int L , int R ) {if( l >= L && r <= R ) {return sum[rt] ;}int m = ( l + r ) >> 1 ;__int64 ans = 0 ;if( L <= m )ans += query( lson , L , R ) ;if( R > m ) ans += query( rson , L , R ) ;return ans ;}void update( int l , int r , int rt , int L , int R , int M ) {if( Max[rt] < M ) return ;if( l == r ) {sum[rt] %= M ;Max[rt] = sum[rt] ;return ;}int m = ( l + r ) >> 1 ;if( L <= m ) {update( lson , L , R , M ) ;}if( R > m ) {update( rson , L , R , M ) ;}pushup( rt ) ;}void update2( int l , int r , int rt , int Index , int key ) {if( l == r ) {sum[rt] = key ;Max[rt] = key ;return ;}int m = ( l + r ) >> 1 ;if( Index <= m ) {update2( lson , Index , key ) ;} else {update2( rson , Index , key ) ;}pushup( rt ) ;}int main(){int n , m ; while( scanf( "%d%d" , &n , &m ) != EOF ) {build( 1 , n , 1 ) ;while( m -- ) {int type ;scanf( "%d" , &type ) ;if( type == 1 ) {int l , r  ; scanf( "%d%d" , &l , &r ) ;printf( "%I64d\n" , query( 1 , n , 1 , l , r ) ) ;} else if ( type == 2 ) {int l , r , x ; scanf( "%d%d%d" , &l , &r , &x ) ;update( 1 , n , 1 , l , r , x ) ;} else {int k , x ;scanf( "%d%d" , &k , &x ) ;update2( 1 , n , 1 , k , x ) ;}}}return 0 ;}


0 0