SDUT ACM 2013级选拔赛(部分题目)

真是没sei了,各种不在状态,又困又累,脑袋就和要炸了一样,也不知道怎么了。四个小时真是一点没浪费,真的算是重新审视了一下自己。这一阵一直乱七八糟的搞来搞去,也没点目的性,算是一直在看算法,算法也没说有多少精进,数学类型靠思维的真的感觉有点无力,反应真的很慢,感觉做题还是太少了,涉猎的面太窄,既然知道了,接下来就去做吧,时间略紧。下面进入正题:


迷之博弈

题目描述

FF喜欢博弈,今天又开始了一场博弈。

n个棋子摆成一条直线,编号为1n。两个人轮流取棋子,每回合取一次且只能按照下述两种方法的一种取。

1,任取一个棋子。

2,任取两个棋子且这两个棋子的编号是连续的。

FF为了彰显高手风范总是让对方先手。现在假设两个人都足够聪明,对于给出的nFF是否能赢。取得最后一个棋子的选手获得胜利。

输入

  多组输入,每组一个正整数 n(1<= n <= 300)

输出

  FF 能胜则输出“ Yeah!, 否则输出“ Why are you so ben?

示例输入

1
2

示例输出

Why are you so ben?
Why are you so ben?


这道题我真是不知道怎么说,一开始直接没画粗来,后来想着原先做过一个圆桌铺硬币,好像是先弄的那个人赢,所以我在想是不是这道题也是这样,然后。。。你懂得,A了。若是某位大牛此时再看,你恰好会,请留言,不胜感激。

#include <stdio.h>
int main()
{
    int n;
    while(~scanf("%d",&n))
    {
        printf("Why are you so ben?\n");
    }
    return 0;
}
 

迷之好奇

题目描述

FF得到了一个有n个数字的集合。不要问我为什么,有钱,任性。

FF很好奇的想知道,对于数字x,集合中有多少个数字可以在x前面添加任意数字得到。

如,x = 123,则在x前面添加数字可以得到4123,5123等。

输入

 多组输入。

对于每组数据

首先输入n(1<= n <= 100000)

接下来n行。每行一个数字y(1 <= y <= 100000)代表集合中的元素。

接下来一行输入m(1 <= m <= 100000),代表有m次询问。

接下来的m行。

每行一个正整数x(1 <= x <= 100000)

输出

 对于每组数据,输出一个数字代表答案。

示例输入

3
12345
66666
12356
3
45
12345
356

示例输出

1
0
1

看到n,m的取值100000是不是吓哭了?我也是这么吓哭的,而且我能说我盯着看了好长时间才看懂这道题么?
思路:用哈希做,储存每一个数值y的后面位数(例如12345,,你可以把它们分解成5,45,345,2345然后把它们当做数组的下标,然后哈希表存储的是该数字的下标有几个,12345就没必要了因为前面不能加,也不可能是它) 另外用哈希做一定要注意 这个地方有一个坑!真是坑哭了,例如10086 当你%100,%1000,%10000的时候都是86,他会把这个当成三次,实际上才一次。所以一定要避开

#include <stdio.h>
#include <math.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <queue>
#include <algorithm>
using namespace std;
int a[100010];
int hash[100010];
int main()
{
    int n,m,x;
    int i,j,t;
    int flag;
    int cnt;
    int site,site1;

    while(~scanf("%d",&n))
    {
        memset(hash,0,sizeof(hash));
    for(i=0; i<n; i++)
        {
            scanf("%d",&a[i]);
            site=a[i]%10;
            cnt=10;
            site1=100;
            for(;;)
            {
                if(site==a[i])
                {
                    break;
                }
                else
                {
                    if(site1!=site)//这个地方,大坑!
                    {
                        hash[site]++;
                        site1=site;
                    }
                    cnt*=10;
                    site=a[i]%cnt;
                }
            }
        }
        scanf("%d",&m);
        for(i=0; i<m; i++)
        {
            scanf("%d",&x);
            printf("%d\n",hash[x]);
        }
    }
    return 0;
}

迷之节约

题目描述

FF 超级有钱,最近又买了 n(1 <= n <= 300) 小岛,为了能在岛之间游玩, FF 决定要在岛之间修桥以保证任意两岛之间都要可达。但是 FF 又超级抠门,想让造桥费用最小。现在由于技术原因,一座桥的造价为两桥之间直线距离的平方。现在给你桥的坐标,让你求最小造价是多少。

输入

 多组输入。
         对于每组数据,第一行输入 n ,接下来的 n 行,每行两个整数 xy(-1000 <= x,y <= 1000) 代表桥的坐标。

输出

  对于每组数据输出一个整数代表最小花费。

示例输入

2
1 1
1 2

示例输出

1

打眼一看这是一道最小生成树的问题,和其余那些裸地差不多,只不过这道题需要你自己计算权值,而且是每个的标号都是每一行的行的行值。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
using namespace std;
#define inf 99999999
int map[310][310];
int dis[310];
int vis[310];
int sum;
struct node
{
    int x,y;
}q[1010];
void prim(int n)
{
    int i,j,k;
    int min;
    sum=0;
    memset(vis,0,sizeof(vis));
    for(i=1;i<=n;i++)
    dis[i]=map[1][i];
    dis[1]=0;
    vis[1]=1;
    for(i=2;i<=n;i++)
    {
        min=inf;
        for(j=1;j<=n;j++)
        {
            if(dis[j]<min&&!vis[j])
            {
                min=dis[j];
                k=j;
            }
        }
        if(min==inf)
           break;
           vis[k]=1;
        sum+=min;
        for(j=1;j<=n;j++)
        {
            if(dis[j]>map[j][k]&&!vis[j])
            {
                dis[j] = map[j][k];
            }
        }
    }
    printf("%d\n",sum);
}

int main()
{
    int n,m;
    int i,j;
    while(~scanf("%d",&n))
    {
        for(i=1;i<=n;i++)
        {
            for(j=1;j<=n;j++)
            {
                if(i==j)
                    map[i][j]=0;
                else
                    map[i][j]=inf;
            }
        }
        for(i=1;i<=n;i++)
        {
            scanf("%d %d",&q[i].x,&q[i].y);
        }
        for(i=1;i<=n;i++)
        for(j=1;j<=n;j++)
                if(i!=j)
                {
                    m=((q[i].x-q[j].x)*(q[i].x-q[j].x) + (q[i].y-q[j].y)*(q[i].y-q[j].y));
                    map[i][j]=map[j][i]=m;
                }

        prim(n);
    }
    return 0;
}


迷之期望

题目描述

FF一直有一个梦想,就是把 CF打到紫名。可是现在有一个问题, FF并不是每场都能涨分。我们现在将这个问题简化,假设现在 FF的分数为 x,每一场增加 a分的概率为 p,增加 0分的概率为 1-p,现在请你计算一下 FF突破 1700的期望场数是多少。

输入

 每组输入 x(0 <= x <= 1700)a (0 <= a <= 100)p (0 <= p <= 1),x,a为整数,p为浮点数

输出

 每组输出输出一行。若能突破 1700,则输出一个浮点数代表答案,保留小数点后三位。

否则输出  Why are you so ben?

示例输入

1700 1 1
1699 100 1
0 0 0

示例输出

0.000
1.000
Why are you so ben?

这道题问的是突破1700分所需要的场次的期望,主要看的是当前分数和1700分的差值。其实在这个题里有几个比较特殊的地方,当你的分数是1700分的时候就是0场,当你的分数比1700分小的时候即差值大于0,如果此时你的加分或者加分的概率是0的话你就一直是笨蛋(这个可能有人忘了)。再说说期望的场次这么个玩意,你要怎么求,如果你的差值取余一场增加的分数的值==0,那么所得结果除以当前的加分概率即可,一开始写的是乘以数据都对,可是忽略了小数。(假设你的差值是4,你的一场加分是2,概率是0.5你怎么求,如果当前的加分概率是1的话你只需要两场就够了,也就是4/2/1,所以换成0.5的话自然是4/2/0.5了) 否则的话要+1,。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <algorithm>
using namespace std;
int main()
{
    int x,a,b;
    int n;
    double p;
    double cnt;
    double qw;
    while(~scanf("%d %d %lf",&x,&a,&p))
    {
        if(x==1700)
            printf("0.000\n");
        else if(x>=0&&x<1700)
        {
            if(a==0||p==0)
                printf("Why are you so ben?\n");
            else
            {
                int b=1700-x;
                if(b%a!=0)
                    cnt=b/a+1;
                    else
                        cnt=b/a;
                          qw=cnt/p;
                          //printf("%d\n",cnt);
            printf("%.3lf\n",qw);
            }

        }

    }
    return 0;
}
 

迷之水题

题目描述

FF有一本密码本,每一页上有一个数字x(1 <= x <= 2000000),并且两两不相等。

可以有一天一个小偷偷走了其中一页,FF想知道小偷偷走了那个数字。

输入

 只有一组输入。

首先一个数组n <= 2000000,代表密码本的页数。

接下来的一行有n个数,代表完整的密码本。

接下来的一行有n-1个数,代表残缺的密码本。

输出

 输出一个整数代表答案。

示例输入

3
1 2 3
3 1

示例输出

2

n的范围是2000000以内,要是开个数组的话一个个的找肯定超时,所以用快排从小到大排序后,然后比对就好。

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
int a[2000010];
int b[2000010];
int main()
{
    int n,i,j;
    int flag=0;
    memset(a,0,sizeof(a));
    memset(b,0,sizeof(b));
    scanf("%d",&n);
    for(i=1;i<=n;i++)
        scanf("%d",&a[i]);
    for(j=1;j<=n-1;j++)
        scanf("%d",&b[j]);
    sort(a+1,a+n+1);
    sort(b+1,b+n);
    for(i=1;i<=n;i++)
    {
        if(a[i]!=b[i])
        {
            printf("%d\n",a[i]);
            flag=1;
            break;
        }
    }
    if(!flag)
        printf("%d\n",a[i-1]);
    return 0;
}






评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Rocky0429

一块也是爱

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值