2017年上海金马五校程序设计竞赛(网上资格赛)部分题目题解


Problem A : Corn's new language


 (Out of Contest)

Time Limit: 1 s

Description

Corn is going to promote programming in the campus, so he wants to add a lot of interesting ideas to make programming more attractive. One task he is working on is to develop a new programming language because he thinks all existing ones are too simple to him. The syntax rules of the language are:

 

1.  () () is a valid program

2.  (P) (P) is a valid program, if  P P is a valid program

3.  PQ PQ is a valid program, if both  P P and  Q Q are valid programs

 

Corn wants a compiler for the language. For a program, if it is valid, the compiler should print the max depth in the program. For example " (()) (())" has a depth of  2 2, while " ((())()) ((())())" has a depth of  3 3. Formally, the max depth is the max number of unmatched open brackets in any prefix.

 

Input

Each case is a non-empty string in a single line, the string will only contain ' ( (' or ' ) )', its length will be no more than  100 100.

 

Output

For each case, output "YES" and the integer required above if the program is valid, separated with a space. Or "NO" if the program is invalid.

 

Sample Input

(
)
()
(())
((())())
())
((

 

Sample Output

NO
NO
YES 1
YES 2
YES 3
NO
NO

题目翻译:

Corn为了在校园里促进编程。他想增加一些有趣的主意使编程更加有吸引力。一个任务是它正在开发一门新的语言因为现存的任何一个语言对它来说都太简单了。这个语言的规则是:
(1)()是 valid 程序
(2) (P)如果P是一个valid程序,那么(P)就是一个valid程序
(3)P和Q都是valid程序,PQ才是valid程序
Corn想要一个语言的编译器。对于一个程序,编译器需要输出程序的最大深度,例如(())的深度是2,
((())())的深度是3.

答案求括号是否匹配,不匹配输出NO,匹配输出YES,并输出括号嵌套的深度。

解题思路:

括号匹配问题,简单模拟题目。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<stack>

using namespace std;

int main()
{
    char str[110];
    while(~scanf("%s",str))
    {
        stack<char>st;
        int len = strlen(str);
        bool match = true;
        int num = 0;
        int mmax = 0;
        for(int i = 0; i < len; i++)
        {
            if(str[i]=='(')
            {
                num++;     ///嵌套层数加1
                mmax = max(mmax,num);
                st.push('(');
            }
            else ///是右括号
            {
                if(st.empty())  ///栈空
                {
                    match = false;
                    break;
                }
                else if(st.top()!='(') ///栈顶不是左括号
                {
                    match = false;
                    break;
                }
                else
                {
                    num--;   ///层数减1
                    mmax = max(mmax,num);
                    st.pop();
                }
            }
        }
        if(!st.empty())  ///最后栈不空
            match = false;
        if(match)
            printf("YES %d\n",mmax);
        else
            printf("NO\n");
    }
    return 0;
}

Problem B : Coach


 (Out of Contest)

Time Limit: 1 s

Description

In the ACM training team, the coach wants to split all students into many groups and each group consists of three students. Let's assume that all students are numbered from  1 1 to  n n. The teacher wants the groups to achieve good results, so he wants to hold the following condition: In a group of three students, they are friends. Also it is obvious that each student must be in exactly one team. If  A A and  B B are friends,  B B and  C C are friends, then  A A and  C C are friends.

 

Input

There are multiple test cases.

For each test case, the first line contains integers  n n and  m m  (1n5000,0m5000) (1≤n≤5000,0≤m≤5000). Then follows  m m lines, each contains a pair of integers  ai,bi ai,bi  (1ai,bin) (1≤ai,bi≤n). The pair  ai,bi ai,bi means that the students  ai ai and  bi bi are friend. It is guaranteed that each pair of  ai ai and  bi bi occurs in the input at most once.

 

Output

If the required group division plan doesn't exist, print “No”. Otherwise, print “Yes”.

 

Sample Input

3 0
6 4
1 2
2 3
4 5
5 6

 

Sample Output

No
Yes
题目翻译:

在ACM训练营,教练把学生分成许多组,每个组都有三个学生,我们假设学生的编号是1~n,教练想让每个组都取得好成绩,因此他想按下面的条件组织,一个组有三个学生,他们是朋友,一个学生只能分到一个组,如果A和B是朋友,B和C是朋友,那么A和C也是朋友(也就是说朋友的朋友也是彼此是朋友)。
让计算是否能成功分队。

解题思路:

我用的广搜,用vector存图,对于一个未访问过的人,统计与它连通的人的人数,并标记这些人,如果人数对3取余有不是0的则输出No,否则输出Yes.

其实感觉题目有问题,一起做的小伙伴,都说开始的时候对人数进行模三判断会wa,我的开始也是先判断模三是否为0,而且还判断m是否为0.结果加

上这句,狂Wa十次,把一开始对三取余和对m的判断删除之后就对了。感觉题目特别有问题。好多人都被这样坑。

还可以用并查集写,好多人都用并查集写的。

让我狂Wa十次的代码,奔溃掉。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<queue>

using namespace std;

const int maxn = 5010;
vector<int>node[maxn];
int vis[maxn];
int n,m;
int bfs(int start)
{
    queue<int>qu;
    vis[start] = 1;
    qu.push(start);
    int num = 0;
    int cur,nex;
    while(!qu.empty())
    {
        cur = qu.front();
        qu.pop();
        num++;
        for(int i = 0; i < node[cur].size(); i++)
        {
            nex = node[cur][i];
            if(vis[nex]==0)
            {
                vis[nex] = 1;
                qu.push(nex);
            }
        }
    }
    return num;
}
int main()
{
    int a,b;
    while(~scanf("%d%d",&n,&m))
    {
        ///如果n根本不是3的倍数,或任何人之间无任何关系
        if(n%3!=0 || m==0)
            printf("No\n");
        else
        {
            memset(vis,0,sizeof(vis));
            memset(node,0,sizeof(node));
            for(int i = 1; i <= m; i++)
            {
                scanf("%d%d",&a,&b);
                node[a].push_back(b);
                node[b].push_back(a);
            }
            int ans;
            bool flag = true;
            for(int i = 1; i <= n; i++)
            {
                if(vis[i]==0)
                {
                    ans = bfs(i);
                    if(ans%3)
                    {
                        flag = false;
                        break;
                    }
                }
            }
            if(flag)
                printf("Yes\n");
            else
                printf("No\n");
        }
    }
    return 0;
}

其实广搜都可以处理n不是3的倍数以及m=0的情况,但是觉得加上上面判断也不会错的,结果WA了十次,感觉WA的莫名其妙,现在也没想到错哪了。

下面是去掉第一句话的AC代码:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<queue>

using namespace std;

const int maxn = 5010;
vector<int>node[maxn];
int vis[maxn];
int n,m;
int bfs(int start)
{
    queue<int>qu;
    vis[start] = 1;
    qu.push(start);
    int num = 0;
    int cur,nex;
    while(!qu.empty())
    {
        cur = qu.front();
        qu.pop();
        num++;
        for(int i = 0; i < node[cur].size(); i++)
        {
            nex = node[cur][i];
            if(vis[nex]==0)
            {
                vis[nex] = 1;
                qu.push(nex);
            }
        }
    }
    return num;
}
int main()
{
    int a,b;
    while(~scanf("%d%d",&n,&m))
    {
        memset(vis,0,sizeof(vis));
        memset(node,0,sizeof(node));
        for(int i = 1; i <= m; i++)
        {
            scanf("%d%d",&a,&b);
            node[a].push_back(b);
            node[b].push_back(a);
        }
        int ans;
        bool flag = true;
        for(int i = 1; i <= n; i++)
        {
            if(vis[i]==0)
            {
                ans = bfs(i);
                if(ans%3)
                {
                    flag = false;
                    break;
                }
            }
        }
        if(flag)
            printf("Yes\n");
        else
            printf("No\n");
    }
    return 0;
}

Problem C : Frog


 (Out of Contest)

Time Limit: 1 s

Description

There is a little frog called Matt. One day he comes to a river. The river could be considered as an axis. Matt is standing on the left bank now (at position  0 0). He wants to cross the river and reach the right bank (at position  N N). But Matt could only jump at most  L L units, for example from  0 0 to  L L. There are  N1 N−1 rocks lying on the river equably (at position  1,2,,N1 1,2,⋯,N−1). The size of the rocks can be ignored, so each rock can be thought as a point on the axis. Matt can jump to a rock from the left bank or other rocks, and he can jump to the right bank from a rock or the left bank.

Now, Matt wants to know how many ways are there to cross the river. Of course, Matt could only jump forward.

 

Input

There are no more than  100 100 cases. Each case contains two integers  N N  (2N100000) (2≤N≤100000) and  L L  (1LN) (1≤L≤N), denoting the position of the right bank and the distance Matt could jump most.

 

Output

For each test case, print the number of way to cross the river module  109+7 109+7.

 

Sample Input

3 1
4 3

 

Sample Output

1
7

题目翻译:

有一只叫Matt的小青蛙,一天他来到了一条河。河可以看成是一个轴,Matt站在最左岸(0位置)。它想过河并到达右河岸(N位置).但是Matt只能跳L个单位长度,例如从0到L,河里面有N-1块石头(等间距的放置)石头的大小可以忽略,因此每块石头可以看成坐标轴上的一个点,Matt可以从左河岸调到其他石头上,他可以从一块石头上跳到右河岸,或者从左岸跳到右岸,现在Matt想知道它有多少种过河方案,当然Matt只能向前跳。
输入:
测试数据不超过100组,每组测试数据包括两个整数N和L,代表右河岸的位置,和Matt能跳的最长的长度。
输出:
对于每组测试数据,输出过河方案对10^9+7的模。

解题思路:

和斐波那契数列相似的递推。

设F[i]为到达地 i 块石头的方案数。

当 i <= L 时

F[0] = 1;

F[1] = F[0] = 1;

F[2] = F[1] + F[0] = 1+1 = 2;

F[3] = F[2] + (F[1]+F[0]) = 2*F[2]

此处可以推得。当 i >= 2 && i <= L时。

F[i] = 2*F[i-1]   

不信的话可以拿数据    5   4 去推,一定是这样的。

当 i > L 时,先定义sum = F[L] = (F[L-1] + F[L-2]  +。。。+F[1] +  F[0]);

因此 i > L 时:

sum = sum - F[i-L-1] + F[i-1];    

意思就是当i = L +1 的时候,sum 是0~L-1项的和,然而当前我要的是1~L这些项的和,所以让sum-F[0]+F[L]  就是从  sum - F[i-L-1] + F[i-1]

然后让 F[i] = sum%mod,但是sum是不能这样一直推下去的,因为后面数太大了,所以sum也需要对题目给定的数取模,取模后就会面临一个问题,sum一旦大于mod,取模后

变成较小的数,而F[i-L-1]其实还是很大的数,这样减法后,sum值会成负数。所以出现这种情况的时候,a[i] = sum + mod。否则a[i] = sum%mod。

当然如果sum成了负数,我们要加上mod使它在成为正数。如果它本身是正数,为了不超过mod,要对mod取余。这题目算是运气好,乱写出来了。

想想为什么要这样,可以想为什么sum会变成负数,一定是sum加到一定值了然后大于mod值了,然后对mod取模,sum变小了,在下次循环减去F[i-L-1]时,F[i-L-1]还是很大的

数,因此sum会变成负值,但是可别忘了,要是不取mod,sum一定是大于F[i-L+1]的,所以sum如果小于0了就要加上mod.


#include<iostream>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>

using namespace std;

const int maxn = 100003;
const long long mod = 1e9+7;
long long a[maxn];
int main()
{
    int N,L;
    while(~scanf("%d%d",&N,&L))
    {
        a[0] = 1;
        a[1] = 1;
        long long sum;
        for(int i = 2; i <= L; i++)
        {
            a[i] = (2*a[i-1])%mod;
        }
        sum = a[L];  ///sum = a[l-1]+a[l-2]+..a[0];
        for(int i = L+1; i <= N; i++)
        {
            sum = sum - a[i-L-1] + a[i-1];
            if(sum < 0)
                a[i] = sum+mod;
            else
                a[i] = sum%mod;
            if(sum<0)
                sum = sum + mod;
            else
                sum = sum%mod;
        }
        printf("%lld\n",a[N]);
    }
    return 0;
}


ACM's Posters


 

Time Limit: 6 s

Description

The members of ACM could not stand that the candidates in the chairman election campaign have been placing their electoral posters at all places in the world. The council has finally decided to build a special electoral wall for placing the posters and introduce the following rules:

 

1. Every candidate can place any poster on the wall.

2. All posters are of the same height equal to the height of the wall; the width of a poster can be any integer number of bytes (byte is the unit of length in ACM world).

3. The wall is divided into segments and the width of each segment is one byte.

4. Each poster must completely cover a contiguous number of wall segments.

 

They have built a wall long enough for all candidates. For simplicity, you can regard it as an interval. When the electoral campaign started, the candidates placed their posters on the wall and their posters differed widely in width. Moreover, the candidates started placing their posters on wall segments already occupied by other posters. Everyone in ACM were curious about the place which is still blank (not occupied by any poster) on the last day before elections.
Your task is to find all blank segments when all the posters are placed given the information about posters' size and place.

 

Input

There are several test cases. For each test case:
The first line contains number  N N  (0N1,000,000) (0≤N≤1,000,000) indicates the number of posters and number  R R  (1R6,626,626,626) (1≤R≤6,626,626,626) indicates the length of the wall. You can regard the wall as an interval  [1,R] [1,R].
The following  N N lines describe the posters pasted on the wall. The  ith ith line among the  N N lines contains two integer number  li li and  ri ri  (1liriR) (1≤li≤ri≤R) which are the number of the wall segment occupied by the left end and the right end of the  ith ith poster respectively. After the  ith ith poster is placed, it entirely covers all wall segments numbered  {li,li+1,,ri} {li,li+1,⋯,ri}.

 

Output

For each test case, print all blank segments after all posters are placed by using minimum number of intervals ordered by left end. If the wall is fully occupied, print "Crazy ACM!" instead.
There is exactly one space after the comma. Make sure not to print extra spaces or lines.

The picture below illustrates the case of the sample input.

 

Sample Input

6 26
1 3
5 6
2 4
14 21
15 15
25 26
2 9
1 5
2 9

 

Sample Output

[7, 13]
[22, 24]
Crazy ACM!
题目翻译:

ACM海报:有N张海报,其高度与墙的高度是相同的,任何人可以往任何地方粘贴海报(意思就是可以覆盖别人的),给出N张海报的宽度范围,给出

海报墙的长度,求未被粘贴的区间,如果整个墙被粘满海报,直接输出Crazy ACM!。

解题思路:

粗略一看觉得是线段树,以n构造线段树,确发现n是海报张数,并不是墙的长度,墙的长度是R,并且高达66亿。

其实很简单的。输入若干海报覆盖的区间后,按照左边界从小到大排序,左边界相等的时候,按右边界从小到大排序。

设置变量left_border来表示前i-1张海报所延伸到的最右侧(就是前i-1张海报覆盖范围的最右侧)。

则对于第 i 张海报,与left_border有三种情形。

情形一:恰好衔接型


像区间【2,4】【5,6】这样恰好衔接住的,left_border+1 == node[i].left.则海报所覆盖到的最右侧要更新。

情形二:区间相交型


这种情况是node[i].left<=left_border。图上是相等情况,当前区间一个是【2,4】一个是【3,5】就是小于号成立的情形了。这种情况海报所覆盖的最右边界需要更新。

情形三:区间相离型。


如图所示类型,这种类型就是区间未被覆盖,输出【left_border+1,node[i].left-1】,然后还是要更新left_border的值,从node[i].right开始。

考虑完所有的海报后,这题没有完,还要看看最终的left_border和R的关系,如果left_border+1<R。则区间left_border+1到R也未被覆盖。

AC代码:

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>

using namespace std;

const int maxn = 1000010;
int N;
long long R;
struct Node
{
    long long left;
    long long  right;
}node[maxn];
bool cmp(struct Node n1,struct Node n2)
{
    if(n1.left==n2.left)
        return n1.right < n2.right;
    else
        return n1.left<n2.left;
}
long long Max(long long a,long long b)
{
    if(a>b)
        return a;
    else
        return b;
}
int main()
{
    while(~scanf("%d%lld",&N,&R))
    {
        for(int i = 0; i < N; i++)
            scanf("%lld%lld",&node[i].left,&node[i].right);
        sort(node,node+N,cmp);
        long long left_border = 0;
        bool flag = true;
        for(int i = 0; i < N; i++)
        {
            ///恰好衔接型
            if(left_border+1==node[i].left)
            {
                left_border = Max(left_border,node[i].right);
            }
            ///区间相交型
            else if(node[i].left<=left_border)
            {
                left_border = Max(left_border,node[i].right);
            }
            else  ///除了上面两种后,就是区间相离型
            {
                printf("[%lld, %lld]\n",left_border+1,node[i].left-1);
                left_border = node[i].right;
                flag = false;
            }
        }
        ///易错点,忘记考虑最终海报覆盖到的最右边界可能没有延伸到墙的最右侧
        if(left_border+1<R)  
        {
            flag = false;
            printf("[%lld, %lld]\n",left_border+1,R);
        }
        if(flag)
            printf("Crazy ACM!\n");
    }
    return 0;
}

 Festival


 (Out of Contest)

Time Limit: 1 s

Description

During the past DHU Club Festival, XiaoTang got many bottles of drinks, but each was of a different taste. And they were not of the same concentration.

Sometimes it's just that confusing with too many choices. XiaoTang decided to mix all of them up to create an extreme unique taste. Please help him. Following is the rule of mixing.

Given the concentrations of each drink:  {c1,c2,,cn} {c1,c2,⋯,cn}, each time you can take  x x  (x2) (x≥2) bottles of drinks and mix them up. It is guaranteed that after your mixing, the concentration become the average number. For example, if you choose three drinks with concentrations of  3 3 4 4 and  8 8, you will get a mixture with a concentration of  5 5. Repeat mixing until there is only one bottle drink left and your aim is to make the final concentration maximal.

Hint: In this problem, we use integer division, eg:  3+22=2 3+22=2.

 

Input

There are several test cases, each contains two lines.

The first line is  n n  (1n100) (1≤n≤100), the number of the drinks.

The second line contains  n n positive integers  ci ci  (1ci100) (1≤ci≤100), the concentration of each drink.

 

Output

For each test case, output the final concentration in a line.

 

Sample Input

2
2 3
1
1

 

Sample Output

2
1

题目翻译:

在过去的DHU节日聚乐会,xiangTang得到许多瓶饮料,但是每一瓶都是一种不同的口味,而且他们不是the same concentration。有时太多的选择会造成困惑,xiaotang打算把他们都混合在一起创造一种极其独特的味道,请你帮助他,给出每种饮料的concentration(c1,c2,cn),每次你都可以用x瓶饮料而且混合他们。保证在混合后concentration会变成这些数的平均数,例如,如果你选择3,4,8,则你会得到5,继续混合知道只有一瓶剩下,你的目的是让最后的concentration最大。输入:多组测试数据,第一行是一个数字N,第二行是N个数字Ci.每瓶饮料的concentration。输出:最后合成一瓶后最大的concentration。解题思路:贪心。采取两两相合的思想,每次取两个最小的相合,直到合完所有的。两两相合后C趋近与较大的了。然后在相合,又向较大的靠拢了。所以先排序,然后两个最小的相合。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>

using namespace std;

int a[103];
int main()
{
    int N;
    while(~scanf("%d",&N))
    {
        for(int i = 1; i <= N; i++)
            scanf("%d",&a[i]);
        sort(a+1,a+1+N);
        for(int i = 2; i <= N; i++)
        {
            a[i] = (a[i]+a[i-1])/2;
        }
        printf("%d\n",a[N]);
    }
}


Problem J : Raising Bacteria


 (Out of Contest)

Time Limit: 1 s

Description

You are a lover of bacteria so you want to raise some bacteria in a box. Initially, the box is empty. Every morning, you can put any number of bacteria into the box. Every night every bacterium in the box will split into two bacteria. You hope to see exactly  x x bacteria in the box at some moment. What is the minimum number of bacteria you need to put into the box across those days?

 

Input

There are several test cases. Each case contains only one integer  x x  (1x109) (1≤x≤109) a line.

 

Output

For each case, output the only line containing one integer: the answer.

 

Sample Input

5
8

 

Sample Output

2
1
题目翻译:

你是一个bacteria的爱好者,因此他想去在盒子里增加一些bacteria.起初,盒子是空的,每天早上,你可以在盒子里放置任意数量的bacteria。每天晚上每一个bacterium会分裂成两个bacteria。在某些时刻你希望看到盒子里面有x个bacteria。那么
你放入盒子的最小细菌数量是多少。

解题思路:

如果当前有t个细菌,那么过一夜会分裂,变成2*t个,因此对于任何偶数x,它由x/2个细菌繁殖过来就好,对于任何奇数y,可以由y-1/2个细菌繁殖过来后在放一个细菌,

因此此题目可以转换成统计2进制数中1的个数。

例如计算繁殖14个细菌,所要放置的最小细菌数,化为2进制:1110

二进制一位是0,是偶数,右移一位变成111 = 7 ;也就是说14可以由7个细菌经过一夜分裂而来;

二进制最后一位是1,是奇数,右移一位变成11,也就是说7可以是3个细菌经过一夜分裂后,在放入一个得来;

二进制最后一位是1,是奇数,右移一位变成1,也就是说3可以是1个细菌经过一夜分裂后,在放入一个得来;

二进制最后一位是1,是奇数,右移一位是0,说明是在第一天最初放进去的1个。

则答案就是3.

分别是第一天放1个,经过一夜繁殖后第二天放入一个,1*2+1 = 3;,然后再经过一夜繁殖后第三天放入一个,3*2+1 = 7,然后经过一夜繁殖,第四天达到要求数目7*2=14

所以答案可以变成统计一个数化为2进制后,统计01串中1的个数就是答案。

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<vector>
#include<algorithm>

using namespace std;

int main()
{
    int x;
    while(~scanf("%d",&x))
    {
        int ans = 0;
        while(x)
        {
            if(x&1) ans++;
            x >>= 1;
        }
        printf("%d\n",ans);
    }
    return 0;
}




  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值