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
原文地址:https://www.cnblogs.com/dramstadt/p/5738355.html