2013暑假集训12级比赛2

A题:

http://acm.hdu.edu.cn/showproblem.php?pid=1412

这题盼神说要用链表,但蛋疼的是我用链表出现上次组队赛中的编译错误,连续三次无解,于是果断使用STL中的链表,这也算是使用了链表吧,哈哈!

STL乃神器也,不解释!

#include <stdio.h>
#include <list>
#include <string.h>
using namespace std;

int main()
{
    int n,m,a[10005],b[10005],i,j;
    while(~scanf("%d%d",&n,&m))
    {
        for(i = 0; i<n; i++)
            scanf("%d",&a[i]);
        for(i = 0; i<m; i++)
            scanf("%d",&b[i]);
        list<int> la;
        list<int> lb;
        for(i = 0; i<n; i++)
            la.push_back(a[i]);
        for(i = 0; i<m; i++)
            lb.push_back(b[i]);
        la.merge(lb);
        la.sort();
        la.unique();//先排序才能去重,否则不行
        int cnt = 0;
        while(!la.empty())
        {
            if(!cnt)
                printf("%d",la.front());
            else
                printf(" %d",la.front());
            cnt++;
            la.pop_front();
        }
        printf("\n");
    }

    return 0;
}


 

B题

http://acm.hdu.edu.cn/showproblem.php?pid=1443

题意:给出一个k,代表有K个好人与K个坏人,其中前K个是好人,后K个是坏人,根据约瑟夫环游戏的原理,在坏人都出局而好人没有一个出局的情况下,m最小是多大

思路:由于k的数值小,直接暴力枚举打表

#include <stdio.h>
#include <string.h>

int main()
{
    int n,a[30],i,j,MIN,jose[14];
    for(i = 1;i<14;i++)
    {
        n = 2*i;
        memset(a,0,sizeof(a));
        MIN = 1;
        for(j = 1;j<=i;j++)
        {
            a[j]=(a[j-1]+MIN-1)%(n-j+1);//(a[j-1]+MIN-1)计算的是从现在这个人的位置开始数能到达的人的位置,(n-j+1)是出局人后一个人的位置,因为要由他开始数,得到的是下个出局的人的位置,注意这个位置是从0开始的
            if(a[j]<i)//好人出局了,j重置,min增加进行枚举
            {
                j = 0;
                MIN++;
            }
        }
        jose[i] = MIN;
    }
    while(~scanf("%d",&n),n)
    {
        printf("%d\n",jose[n]);
    }

    return 0;
}

 

C题

http://acm.hdu.edu.cn/showproblem.php?pid=3336

题意:给以字符串 计算出以前i个字符为前缀的字符中 在主串中出现的次数和

             如: num(abab)=num(a)+num(ab)+num(aba)+num(abab)=2+2+1+1=6;

题解:next[i]记录的是长度为i 不为自身的最大首尾重复子串长度  num[i]记录长度为next[i]的前缀所重复出现的次数

#include <stdio.h>
#include <string.h>
using namespace std;
#define MAXN 200005
#define MOD 10007

int next[MAXN],sum[MAXN],n;
char str[MAXN];

void getnext()//kmp的next数组,不解释
{
    int i = 0,j = -1;
    next[0] = -1;
    while(str[i])
    {
        if(j == -1 || str[i] == str[j])
        {
            ++i;
            ++j;
            next[i] = j;
        }
        else
            j = next[j];
    }
}


int main()
{
    int t,ans;
    scanf("%d",&t);
    while(t--)
    {
        getchar();
        scanf("%d",&n);
        ans = 0;
        memset(sum,0,sizeof(sum));
        scanf("%s",str);
        getnext();
        for(int i = 1; i<=n; i++)
            sum[next[i]] = (sum[next[i]]+1)%MOD;
        for(int i = 1; i<=n; i++)
            ans=(ans+sum[i]+1)%MOD;
        printf("%d\n",ans);
    }

    return 0;
}


 

D题

http://acm.hdu.edu.cn/showproblem.php?pid=1022

题意:给出进站与出栈的顺序,看能否顺利出站

思路:再一次STL,估计也就我这种没节操的在用STL做了吧?嘎嘎,再一次证明STL的神奇

#include <stdio.h>
#include <stack>
#include <string.h>
using namespace std;

int main()
{
    stack<int> S;
    int n,i,j,k;
    int flag[1000];
    char in[1000],out[1000];
    while(~scanf("%d",&n))
    {
        scanf("%s%s",in,out);
        i = j = k = 0;
        while(i<n && j<n+1)
        {
            if(!S.empty() && S.top() == out[i])//如果栈顶元素与现在出站的车号相等
            {
                i++;
                flag[k] = 1;
                k++;
                S.pop();//删除栈顶元素
            }
            else
            {
                S.push(in[j]);
                flag[k] = 0;
                j++;
                k++;
            }
        }
        if(k!=2*n)//k没有计算2*n次的话,肯定不符合
        {
            printf("No.\n");
        }
        else
        {
            printf("Yes.\n");
            for(i = 0;i<k;i++)
            {
                if(flag[i])
                printf("out\n");
                else
                printf("in\n");
            }
        }
        printf("FINISH\n");
    }


    return 0;
}


E题

http://acm.hdu.edu.cn/showproblem.php?pid=3328

题意:其实这题并不难,只是题意有点难理解

首先给出每张牌的初始状态,U为面朝上,D为面朝下,然后跟着几个操作,L代表从左边翻,R代表从右边翻

例如第一个样例,前两个R,代表最右边的5翻转,叠放到4上,然后这两张叠放的一起翻转,叠放到3上

剩下的两个L,代表最左边的1翻转,叠峰到2上,然后这两张再一起翻转,叠放到3,4,5形成的堆上,然后他们就成为了一堆

最后给出n询问,询问这一堆的第几张牌是什么状态

例如Card 1 is a face down 2.就是说这个堆的第一张牌是面朝下的2

 

思路:知道题意就可以直接开始模拟了

#include <stdio.h>
#include <string.h>
using namespace std;

struct node
{
    int face,num;
}card[105][105];

int ip[105],work[105];

void turn(int x,int y)
{
    int i;
    for(i=ip[x];i>=1;i--)
    {
        if(card[x][i].face)//翻转的过程
        card[x][i].face = 0;
        else
        card[x][i].face = 1;
        card[y][++ip[y]] = card[x][i];//二维数组记录堆的状况
    }
}

int main()
{
    int cas = 1;
    int n,m,i,j;
    char str[105],done[105];
    while(~scanf("%d",&n),n)
    {
        scanf("%s%s",str,done);
        memset(ip,0,sizeof(ip));
        for(i = 0;i<n;i++)
        {
            card[i+1][1].num = i+1;
            if(str[i] == 'U')
            card[i+1][1].face = 1;
            else
            card[i+1][1].face = 0;
            ip[i+1] = 1;
        }
        int l = 1,r = n;
        for(i = 0;i<n-1;i++)//翻转过程
        {
            if(done[i] == 'R')
            {
                turn(r,r-1);
                r--;
            }
            else
            {
                turn(l,l+1);
                l++;
            }
        }
        scanf("%d",&m);
        for(i = 1;i<=m;i++)
        {
            scanf("%d",&work[i]);
        }
        printf("Pile %d\n",cas++);
        for(i = 1;i<=m;i++)
        {
            if(card[r][n-work[i]+1].face==1)//这里和r都是可以的,因为最后他们必然叠放在同一堆,l=r
            printf("Card %d is a face up %d.\n",work[i],card[r][n-work[i]+1].num);
            else
            printf("Card %d is a face down %d.\n",work[i],card[r][n-work[i]+1].num);
        }
    }

    return 0;
}


F题

http://acm.hdu.edu.cn/showproblem.php?pid=1870

题意:上次比赛就出过了,我就不解释了

思路:我用STL我骄傲

#include <stdio.h>
#include <stack>
#include <string.h>
using namespace std;

int main()
{
    stack<char> S;
    char str[1005];
    int i,j,len,cnt;
    while(gets(str))
    {
        while(!S.empty())
            S.pop();
        len = strlen(str);
        cnt = i = 0;
        while(i<len)
        {
            if(str[i]=='(')
            {
                S.push(str[i]);
                i++;
                cnt++;
            }
            else
            {
                if(str[i]==')')
                {
                    S.pop();
                    cnt--;
                    i++;
                }
                else
                break;
            }
        }
        if(!S.empty())
        printf("%d\n",cnt);

    }

    return 0;
}


G题

http://acm.hdu.edu.cn/showproblem.php?pid=1702

题意:FIFO-先进先出,明显是队列

FILO-先进后出,这就是栈

IN就是往栈或者队列里末尾插入一个数字

OUT就是显示出队列或者出栈的元素

思路:赤裸裸的STL

#include <stdio.h>
#include <queue>
#include <stack>
#include <string.h>
using namespace std;

void que(int n)
{
    queue<int> Q;
    char s[10];
    int a;
    while(n--)
    {
        scanf("%s",s);
        if(!strcmp(s,"IN"))
        {
            scanf("%d",&a);
            Q.push(a);
        }
        else
        {
            if(Q.empty())
            printf("None\n");
            else
            {
                printf("%d\n",Q.front());
                Q.pop();
            }
        }
    }
}

void sta(int n)
{
    stack<int> S;
    char s[10];
    int a;
    while(n--)
    {
        scanf("%s",s);
        if(!strcmp(s,"IN"))
        {
            scanf("%d",&a);
            S.push(a);
        }
        else
        {
            if(S.empty())
            printf("None\n");
            else
            {
                printf("%d\n",S.top());
                S.pop();
            }
        }
    }
}


int main()
{
    int n,t;
    char str[100];
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d%s",&n,str);
        if(!strcmp(str,"FIFO"))
        que(n);
        else if(!strcmp(str,"FILO"))
        sta(n);
    }

    return 0;
}

 

H题

http://acm.hdu.edu.cn/showproblem.php?pid=4414

题意:找出十字架的个数,要注意十字架旁边不能有#

思路:直接模拟

这题早在盼神开的专题中就有了,然后盼神唠叨的说,这道没人做,要出来做比赛题,于是我果断上午就做了,然后下午果断就出现了,然后果断就A了,没节操啊没节操

#include <stdio.h>
#include <string.h>

char map[55][55];

int main()
{
    int n,i,j,k,ans,flag;
    while(~scanf("%d",&n),n)
    {
        ans = 0;
        for(i = 0; i<n; i++)
            scanf("%s",map[i]);
        int cnt1,cnt2,cnt3,cnt4;
        for(i=1; i<n-1; i++)
        {
            for(j=1; j<n-1; j++)
            {
                flag=1;
                if(map[i][j]=='#')//这个#是中间的
                {
                    cnt1=cnt2=cnt3=cnt4=0;
                    for(k=i-1; k>=0; k--)//向上找
                    {
                        if(map[k][j]=='#')
                        {
                            if(map[k][j-1]=='#'||map[k][j+1]=='#')//每找一个看这个的上下是否有#,有则不是要求的十字架
                            {
                                flag=0;
                                break;
                            }
                            cnt1++;//统计向上伸长的长度
                        }
                        else break;
                    }
                    if(cnt1<1) flag=0;//由于十字架长度要最少为3,所以小于1肯定不行
                    for(k=i+1; k<n&&flag; k++)//下向
                    {
                        if(map[k][j]=='#')
                        {
                            if(map[k][j-1]=='#'||map[k][j+1]=='#')
                            {
                                flag=0;
                                break;
                            }
                            cnt2++;
                        }
                        else break;
                    }
                    if(cnt1!=cnt2) flag=0;//上下不等,肯定不是十字架
                    for(k=j-1; k>=0&&flag; k--)//左向
                    {
                        if(map[i][k]=='#')
                        {
                            if(map[i-1][k]=='#'||map[i+1][k]=='#')
                            {
                                flag=0;
                                break;
                            }
                            cnt3++;
                        }
                        else break;
                    }
                    if(cnt3<1) flag=0;
                    for(k=j+1; k<n&&flag; k++)//右向
                    {
                        if(map[i][k]=='#')
                        {
                            if(map[i-1][k]=='#'||map[i+1][k]=='#')
                            {
                                flag=0;
                                break;
                            }
                            cnt4++;
                        }
                        else break;
                    }
                    if(cnt3!=cnt4) flag=0;
                    if(flag) ans++;//所有条件符合,个数加1
                }
            }
        }
        printf("%d\n",ans);
    }

    return 0;
}


 

总的来说,这次的题目还是挺水的= =

你可能感兴趣的:(2013暑假集训12级比赛2)