湖南工业大学第一届ACM程序设计大赛

99 篇文章 0 订阅
95 篇文章 0 订阅



                      分糖果

时间限制(普通/Java):1000MS/3000MS          运行内存限制:65536KByte
总提交:14            测试通过:11

描述

 

肖恩和帕特里克是兄弟,他们从他们的父母那里得到了很多糖果。每一块糖具有一个的正整数的价值,孩子们希望分他们得到的糖果。首先,肖恩将这些糖果分成两堆,并选择一堆给帕特里克。然后,帕特里克将尝试计算每堆的价值,其中每堆的价值是在那堆的糖果价值的总和,如果他觉得没有平等的价值,他将开始哭了起来。

不幸的是,帕特里克太小了,所以不能正确的计算。他只会二进制无进位的加法。比如说,他想算12(二进制为1100)加5(二进制为101),他会把最右边的两位加法算正确,但是第三位会忘记进位。(即0+0=0,0+1=1,1+0=1,1+1=0)

因此,帕特里克算125的结果为9下面几个是帕特里克算的结果:

5 + 4 = 1

7 + 9 = 14

50 + 10 = 56

肖恩数学很好,他想得到价值总和更高的糖果并且不让他的弟弟哭。如果可能,他会分成两个非空的糖果袋,让帕特里克认为,双方都有相同的值的糖果。给你每一袋糖果每一块糖果的价值,我们想知道是否可能让帕特里克相信他们得到糖果价值的总量是相同的。如果可能计算出肖恩能得到的最大的价值。


输入

第一行输入T(1<T<1000)组测试数据。接下来是T行,每行包含以下数据,N C1 C2 .. Cn
(N(2 ≤ N ≤ 1000)代表从父母那里得到糖果的总数,C(1 ≤ Ci ≤ 10^6)代表每块糖果的价值)

输出

若不能输出NO,若能则输出肖恩得到的最大的价值。

样例输入

2
5 1 2 3 4 5
3 3 5 6

样例输出

NO
11

  天哪, 刚看见这道题目,就觉得无从下手,只知道这是道跟数字过不去的题目,无进位加法,看似从未接触过,写成程序的话也是繁杂冗长,比赛时间宝贵,没有灵感还不是直接跳过这道题目,就这样放弃了这道题目。

  赛后,听了解题发布会,才知道这个要用异或位运算来处理 即 对应二进制中的每一位 1+1=0、0+0=0、1+0=1,0+1=1,而且更令人匪夷所思的是,判定题中是否能够平分成两半的条件就是把所有的数字二进制无进位相加,如果最后的结果 不为零 的话,那么说明这种分法不成立。 而如果相加的结果等于零的话,只需将最小的那个数给弟弟就可以了...... 这里又是一个比较神奇的地方,即N个数的二进制无进位加法结果为零的话,那么无论怎样去分开这N个数,分成的两部分的结果分别做无进位加法后的结果一样 例如 | 3 5 6 | ,  3(10) = 011(2)  , 5(10) = 101(2) , 6(10) = 110(2)  , 进行无进位加法后 101(2) + 110(2) = 011(2) = 3(10) ,这样一下来,代码就异常简单了 如下:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<time.h>
 
 
int  N,T;
 
int  main()
{
     scanf ( "%d" ,&T);
     while (T--)
     {
         int  min=0x7fffffff,temp=0;
         int  sum=0;
         scanf ( "%d" ,&N);
         while (N--)
         {
             
             int  c;
             scanf ( "%d" ,&c);
             min = min < c ? min : c;
             temp ^= c;
             sum+=c;
         }
         if (temp!=0)
             puts ( "NO" );
         else
             printf ( "%d\n" ,sum-min);
         
     }
     return  0;
}


                     数字游戏

时间限制(普通/Java):1000MS/3000MS          运行内存限制:65536KByte
总提交:53            测试通过:10

描述

 

现在,有许多给小孩子玩的数字游戏,这些游戏玩起来简单,但要创造一个就不是那么容易的了。 在这,我们将介绍一种有趣的游戏。

你将会得到N个正整数,你可以将一个整数接在另一个整数之后以制造一个更大的整数。 例如,这有4个数字123, 124, 56, 90,他们可以制造下列整数─ 1231245690, 1241235690, 5612312490, 9012312456, 9056124123....等,总共可以组合出24(4!)种数字。 但是,9056124123是最大的那一个。

你可能会想这是个简单的事情,但对刚有数字概念小孩来说,这会是个简单的任务吗?


输入

输入含有多组测试资料。 每组测试资料两列,第一列为一个正整数N(N <= 50),下一列将有N 个正整数。 当N=0代表输入结束。

输出

对每一笔 测试资料 输出一列,输出利用这N个整数可结合成的最大整数。

样例输入

4
123 124 56 90
5
123 124 56 90 9
5
9 9 9 9 9
3
12 123 1231
0

样例输出

9056124123
99056124123
99999
123123112

提示

对于这类题目,输入可以采用如下的方式:

int n;
while(scanf("%d", &n) != EOF){
    your code...
}

  

  看似是一道数学题目,但是谁都知道,这算是一个排序的题目,而且并不是普通的排序,从样例中可以窥见,仅仅靠 一个 strcmp  (不做其他处理)是不能够正确排出序来的,虽然可以将 "124" 和 "123" 正确处理,但是 "90" 和 "9" 便不能够正确的排列出来,90对应的是'9' '0' '\0' 而 9 对应的是 '9' '\0'  ,其中strcmp函数是判定到一个字符串结束为止,'\0'在数值上是等于 0 的,所以 "90">"9" ,而实际上"909"<"990",从这里我们可以找到一点排序的思路了,即将两个相邻的字符串 分别进行 正接 和 反接 后,判定哪个大,这个时候可以用到 strcmp函数了,按优先大的拼接方式进行排序。

 

代码如下:

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<time.h>
 
 
char  str[55][1000];
 
int  cmp( const  void  *a , const  void  *b)
{
     char  p1[1000],p2[1000];  // 比赛中因为数组开小了,而......
     strcpy (p1,( char  *)a);    // 做临时存储,这是由于数组即指针常量的关系
     strcpy (p2,( char  *)b);
     strcat (p1,( char  *)b);    // 不要在 a,b 上直接拼接啊。
     strcat (p2,( char  *)a);
     return  strcmp (p2,p1);
}
 
int  main()
{
     int  N;
     while ( scanf ( "%d" ,&N),N)
     {
         for ( int  i=0;i<N;++i)
             scanf ( "%s" ,str[i]);
         qsort (str,N, sizeof (str[0]),cmp);
         for ( int  i=0;i<N;++i)
             printf ( "%s" ,str[i]);
         puts ( "" );
     }
     return  0;
}
My  code:
#include<iostream>
#include<algorithm>
#include<cstdlib>
#include<cstdio>
#include<cstring>
using namespace std;
char str[55][1111];
int cmp(const void *a,const void *b)//注意:对字符串排序最好用qsort,不用sort! 
{
	char s1[1111],s2[1111];
	strcpy(s1,(char *)a);
	strcpy(s2,(char *)b);
	strcat(s1,(char *)b);
	strcat(s2,(char *)a);
	if(strcmp(s1,s2)>=0)//从大到小进行排序 
	return -1;
	else
	return 1;
}
int main()
{
	int n,i;
	while(scanf("%d",&n)&&n)
	{
		for(i=0;i<n;i++)
		{
			scanf("%s",str[i]);
		}
		qsort(&str[0],n,sizeof(str[0]),cmp);
		for(i=0;i<n;i++)
		printf("%s",str[i]);
		puts("");
	}
	return 0;
}


我素故我在
时间限制(普通/Java):1000MS/3000MS          运行内存限制:65536KByte
总提交:17            测试通过:9

描述

有这样一种素数叫纯素数(YY出来的名字),当它是一个多位数的时候,你把它的末位去掉之后余下的数依然是一个素数。比如说2393,2393 本身是一个素数,它的末位去掉之后,余下的是239。239 是一个素数,它的末位去掉之后,余下的是23 。23是一个素数,它的末位去掉之后,余下的是2 。2依然还是一个素数。纯素数的长度叫做“维”。2393 是一个4维素数。3797也是一个4维素数。


输入

  
输出

按照从小到大的顺序输出所有的T维纯素数。

样例输入

1
1

样例输出

2
3
5
7

 
 
  这次校赛得一个很有意思的一题,比赛完之后的解题报告中得知用DFS做的这道题,而比赛中我却始终想用循环写出这道题目......到底是道行不够深啊,没有掌握DFS的根本属性,本题中有一个关键的条件,而这个条件就是决定了这道题目用DFS做是最契合题意的,这句话就是“当它是一个多位数的时候,你把它的末位去掉之后余下的数依然是一个素数” 这说明了后面的判断是和前一次的判断是有联系的。再者,我们可以预想到 四位数 的纯素数 肯定和 三位数 、五位数 的 纯素数有关系,因此,一次DFS能够算出你想要的所有值,由于这里N的取值可能很大,所以在改进了一下下,DFS+打表,即在询问之前,将所有的对应的纯素数均计算出来,并用数组存储好,这样的后面的询问便可很快的输出来。
代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
#include<time.h>
 
// 由于N 的取值可以很大,所以打表过,即首先
// 算出 1- 8 的所有纯素数的的值,存起来,以后每次询问时
// 便直接打印就行。
// 但虽说如此,用管理员号看了下测试数据,很水,N=8.....
 
int  num[10][100],N;   // num用来存储纯素数
 
int  l[10];   // 用来存储对应位数限制的纯素数的个数
 
bool  isp( int  x)   // 模板化的判断素数函数
{
     if ( x<=1 )
         return  0;
     if ( x==2 )
         return  1;
     int  lim = (  int  sqrt ( x ) ;
     for ( int  i = 2; i <= lim; ++i)
         if ( !( x % i ) )
             return  false ;
     return  true ;
}
 
void  DFS(  int  x,  int  len, int  cnt)
{
     if (len>8)
         return  ;
     num[len][cnt]=x;   // 由于进来后是无条件的存储该值
     for ( int  i=1;i<10;++i)  //所以必须保证传入的参数质量达标
     {
         if (isp(10*x+i))   // 保证传入的均为纯素数
             DFS(10*x+i,len+1,++l[len+1]);
     }
}
 
int  main()
{
     for ( int  i=2;i<10;++i)
     {
         if (isp(i))   // 与DFS中作用一样
             DFS(i,1,++l[1]); // 刚开始把第三个参数赋值为 1,结果ask=1时
     }                        // 无结果,后来知道是那样 l[1] 根本没有赋值
     scanf ( "%d" ,&N);
     while (N--)
     {
         int  ask;
         scanf ( "%d" ,&ask);
         for ( int  i=1;i<=l[ask];++i)  //注意从 1开始 因为参数传的是 ++l[x]
             printf ( "%d\n" ,num[ask][i]);
     }
     return  0;
}

My code:

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
using namespace std;
bool isp(int num)
{
	if(num<2)
	return false;
	if(num==2)
	return true;
	int k=sqrt(num);
	for(int i=2;i<=k;i++)
	{
		if(num%i==0)
		return false;
	}
	return true;
 } 
 int cun[11][111];
 int len_cnt[9];
 void dfs(int n,int len,int cnt)
 {
 	if(len>8)
 	return;
 	cun[len][cnt]=n;
 	for(int i=1;i<=9;i++)
 	{
 		if(isp(n*10+i))
 		dfs(n*10+i,len+1,++len_cnt[len+1]);
	 }
 }
 int main()
 {
 	int T,i,ask;
 	for(i=2;i<=9;i++)
 	{
 		if(isp(i))
 		{
 			dfs(i,1,++len_cnt[1]);
		 }
	 }
 	while(scanf("%d",&T)==1)
 	{
 		while(T--)
 		{
 			scanf("%d",&ask);
 			for(i=1;i<=len_cnt[ask];i++)
 			printf("%d\n",cun[ask][i]);
		 }
 		
	 }
	 return 0;
 }


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值