• Codeforces Round #363 Div.2[111110]


    好久没做手生了,不然前四道都是能A的,当然,正常发挥也是菜。

    A:Launch of Collider

      题意:20万个点排在一条直线上,其坐标均为偶数。从某一时刻开始向左或向右运动,速度为每秒1个单位长度。输入给出每个点的坐标及其移动的方向,求发生第一次碰撞的时间,若不会碰撞,则输出-1

      最先发生碰撞的是一定是初始时相邻的两个点,因此只需对每个点循环一边,判断其是否会与下一个点碰撞,并求出其时间即可。

    #include<stdio.h>
    #include<stdlib.h>
    int N;
    int pos[200100];
    char ch[200100];
    char st[200100];
    int main()
    {
        scanf ( "%d", &N );
        getchar();
        for ( int i = 1; i <= N; i++ ) scanf ( "%c", &ch[i] );
        for ( int i = 1; i <= N; i++ ) scanf ( "%d", &pos[i] );
        int ans = 0x7FFFFFFF, p = 0;
        for ( int i = 1; i <= N; i++ )
        {
            if ( ch[i] == 'R' )
            {
                p = i;
                continue;
            }
            if ( p == 0 ) continue;
            if ( ( pos[i] - pos[p] ) / 2 < ans ) ans = ( pos[i] - pos[p] ) / 2;
        }
        if ( ans == 0x7FFFFFFF ) printf ( "-1
    " );
        else printf ( "%d
    ", ans );
        return 0;
    }
    View Code

    B:One Bomb

      题意:1000*1000的矩阵,‘.’表示空地,‘*’表示围墙。可以在任意位置按一颗炸弹,摧毁位于同一行和同一列的所有墙。问对于给定的地图,能否只用一颗炸弹炸掉所有墙。

      首先随意指定一个墙点,将其坐标与其他所有墙点比较,如果其他墙点与这个点要么在同一行,要么在同一列,则可以完成,否则能找到一个与第一个点既不在同一行也不在同一列的墙点。根据这两个点可以确定两个位置,炸弹如果要摧毁所有的墙,只能在这两个点中选择一个,分别尝试并确认即可。

    #include<stdio.h>
    int p[1001000][2];
    char str[1005][1005];
    int main()
    {
        int N, M;
        scanf ( "%d%d", &N, &M );
        for ( int i = 1; i <= N; i++ ) scanf ( "%s", &str[i][1] );
        int T = 0;
        for ( int i = 1; i <= N; i++ )
            for ( int j = 1; j <= M; j++ )
                if ( str[i][j] == '*' )
                {
                    p[++T][0] = i;
                    p[T][1] = j;
                }
        if ( T == 0 )
        {
            printf ( "YES
    1 1
    " );
            return 0;
        }
        bool find = false;
        int x, y;
        for ( int i = 2; i <= T; i++ )
            if ( p[i][0] != p[1][0] && p[i][1] != p[1][1] )
            {
                find = true;
                x = p[i][0];
                y = p[i][1];
                break;
            }
        if ( !find )
        {
            printf ( "YES
    " );
            printf ( "%d %d
    ", p[1][0], p[1][1] );
            return 0;
        }
        else
        {
            bool planA = true, planB = true;
            int x1 = x, y1 = p[1][1];
            for ( int i = 1; i <= T; i++ )
                if ( p[i][0] != x1 && p[i][1] != y1 )
                {
                    planA = false;
                    break;
                }
            int x2 = p[1][0], y2 = y;
            for ( int i = 1; i <= T; i++ )
                if ( p[i][0] != x2 && p[i][1] != y2 )
                {
                    planB = false;
                    break;
                }
            if ( !planA && !planB )
            {
                printf ( "NO
    " );
                return 0;
            }
            printf ( "YES
    " );
            printf ( "%d %d
    ", planA ? x1 : x2, planA ? y1 : y2 );
        }
        return 0;
    }
    View Code

    C:Vacations

      题意:每天可以有3种选择,发呆,锻炼身体或者打比赛,连着两天如果不发呆则做的事不能相同。求发呆的最少天数。

      f[i][0]表示到第i天位置且当天发呆的最小发呆天数,f[i][1]表示当天锻炼身体,f[i][2]表示当天打比赛。

    #include<stdio.h>
    int MIN2 ( int a, int b )
    {
        return a < b ? a : b;
    }
    int MIN3 ( int a, int b, int c )
    {
        int t = 10000;
        if ( t > a ) t = a;
        if ( t > b ) t = b;
        if ( t > c ) t = c;
        return t;
    }
    int f[200][5];
    int d[200];
    int main()
    {
        int N;
        scanf ( "%d", &N );
        for ( int i = 1; i <= N; i++ ) scanf ( "%d", &d[i] );
        f[0][0] = 0;
        f[0][1] = 1000;
        f[0][2] = 1000;
        for ( int i = 1; i <= N; i++ )
        {
            if ( d[i] == 0 )
            {
                f[i][0] = MIN3 ( f[i - 1][0], f[i - 1][1], f[i - 1][2] ) + 1;
                f[i][1] = 1000;
                f[i][2] = 1000;
            }
            if ( d[i] == 1 )
            {
                f[i][0] = MIN3 ( f[i - 1][0], f[i - 1][1], f[i - 1][2] ) + 1;
                f[i][1] = MIN2 ( f[i - 1][0], f[i - 1][2] );
                f[i][2] = 1000;
            }
            if ( d[i] == 2 )
            {
                f[i][0] = MIN3 ( f[i - 1][0], f[i - 1][1], f[i - 1][2] ) + 1;
                f[i][1] = 1000;
                f[i][2] = MIN2 ( f[i - 1][0], f[i - 1][1] );
            }
            if ( d[i] == 3 )
            {
                f[i][0] = MIN3 ( f[i - 1][0], f[i - 1][1], f[i - 1][2] ) + 1;
                f[i][1] = MIN2 ( f[i - 1][0], f[i - 1][2] );
                f[i][2] = MIN2 ( f[i - 1][0], f[i - 1][1] );
            }
        }
        printf ( "%d
    ", MIN3 ( f[N][0], f[N][1], f[N][2] ) );
        return 0;
    }
    /*
           8
           1 1 1 1 1 1 1 2
    0 0    1 1 2 2 3 3 4 4
    1 x    0 1 1 2 2 3 3 x
    2 x    x x x x x x x 3
    1->0,1
    2->0,2
    3->0,1,2
    */
    View Code

    D:Fix a Tree

      题意:给定n个点各自的父亲,得到一个n个点n条边的有向图。每次可以修改一个点的父亲,求最少修改多少次才能得到一棵树(树的根节点的父亲是其自身)。

      首先在给出的点里找到一个父亲是自身的点作为根节点,然后从图中搜索环,并把环上任意一点的父亲改为根节点。若找不到父亲为自身的点,则任意找到图中的一个环,从环上断开,并将断点的父亲修改为自身,作为根节点,并重复之前的步骤。

    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    int fa[210000];
    bool v[210000], u[210000];
    int main()
    {
        int N, Root = -1, cnt;
        scanf ( "%d", &N );
        for ( int i = 1; i <= N; i++ ) scanf ( "%d", &fa[i] );
        memset ( v, false, sizeof ( v ) );
        for ( int i = 1; i <= N; i++ )
            if ( fa[i] == i )
            {
                Root = i;
                v[i] = true;
                break;
            }
        if ( Root != -1 )
        {
            cnt = 0;
            for ( int i = 1; i <= N; i++ )
                if ( !v[i] )
                {
                    memset ( u, false, sizeof ( u ) );
                    int x = i;
                    v[x] = true;
                    u[x] = true;
                    while ( !v[fa[x]] )
                    {
                        v[fa[x]] = true;
                        u[fa[x]] = true;
                        x = fa[x];
                    }
                    if ( u[fa[x]] )
                    {
                        cnt++;
                        fa[x] = Root;
                    }
                }
        }
        else
        {
            Root = 1;
            v[1] = true;
            while ( !v[fa[Root]] )
            {
                v[fa[Root]] = true;
                Root = fa[Root];
            }
            cnt = 1;
            fa[Root] = Root;
            for ( int i = 1; i <= N; i++ )
                if ( !v[i] )
                {
                    memset ( u, false, sizeof ( u ) );
                    int x = i;
                    v[x] = true;
                    u[x] = true;
                    while ( !v[fa[x]] )
                    {
                        v[fa[x]] = true;
                        u[fa[x]] = true;
                        x = fa[x];
                    }
                    if ( u[fa[x]] )
                    {
                        cnt++;
                        fa[x] = Root;
                    }
                }
        }
        printf ( "%d
    ", cnt );
        for ( int i = 1; i < N; i++ ) printf ( "%d ", fa[i] );
        printf ( "%d
    ", fa[N] );
        return 0;
    }
    View Code

    E:LRU

      题意:自己读吧,懒得写了。

      题目里问1e100次后的概率,显然不用真的算到1e100,它只是表示一个“足够多”的概念。由于每种目标或者有或者没有只有两种状态,而目标的数目最多20个,因此可以用一个20位的二进制数表示所有可能的状态。经过足够多的次数后,槽位全部被填满,此后的状态转移并不影响概率。因此对于每一种状态,只需计算刚刚好达到这种状态的概率即可,也就是说,不用考虑弹出之前的某个目标的情况。

    #include<stdio.h>
    int N, K;
    double p[22];
    double ans[22];
    double dp[1 << 20 + 100];
    int main()
    {
        int k;
        double sp;
        scanf ( "%d%d", &N, &K );
        for ( int i = 0; i < N; i++ )
        {
            scanf ( "%lf", &p[i] );
        }
        dp[0] = 1;
        for ( int i = 1; i < ( 1 << N ); i++ )
        {
            sp = 0;
            k = 0;
            for ( int j = 0; j < N; j++ )
            {
                if ( ( ( 1 << j ) &i ) == 0 )
                {
                    sp += p[j];
                    k++;
                }
            }
            if ( N - k > K ) continue;
            for ( int j = 0; j < N; j++ )
            {
                if ( p[j] < 0.000000001 ) continue;
                if ( ( ( 1 << j ) &i ) != 0 )
                {
                    dp[i] += dp[i - ( 1 << j )] * p[j] / ( sp + p[j] );
                    ans[j] += dp[i - ( 1 << j )] * p[j] / ( sp + p[j] );
                }
            }
        }
        for ( int i = 0; i < N; i++ )
        {
            printf ( "%.10lf ", ans[i] );
        }
        return 0;
    }
    View Code
  • 相关阅读:
    html,css,javascript 总结
    Java总结2
    Java总结1
    Java学习第5天
    Java学习第4天
    Java学习第3天
    java 学习第二天
    java学习第一天
    markdown 学习
    django——django链接mysql数据库
  • 原文地址:https://www.cnblogs.com/dramstadt/p/5738355.html
Copyright © 2020-2023  润新知