JSU 2013 Summer Individual Ranking Contest - 6
密码:本套题选题权归JSU所有,需要密码请联系(http://blog.csdn.net/yew1eb)。
一、套题分析:该套题难度不太大,适合有一定基础的ACMer用于练习。
二、考点:逻辑思维的活跃性、三角形基本性质、数学函数基本性质、字符串处理、大数处理、二分法、动态规划
三、竞赛形式:个人赛
四、解题时间:3小时
五、题目情况:
A. Ants
B. Best Cow Line
C. 1sting
D. Can you solve this equation?
E. Triangular Pastures
六、解题报告:
A. Ants
Input
Output
Sample Input
2
10 3
2 6 7
214 7
11 12 7 13 176 23 191
Sample Output
4 8
38 207
解题思路:本题只要搞清题目本质问题,便是简单题,若是以一般思维,则是难题。
有n只蚂蚁在竹竿上,竹竿上的位置从0到l(竹竿的长度),每只蚂蚁可以向左或向右走,相遇后分别反向,继续走。给出t,代表有t组数据,每组数据有2行。第一行两个数l,n分别代表竹竿长度和蚂蚁个数。第二行是每个蚂蚁所在竹竿上的坐标。
很多人,看到“相遇后分别反向,继续走”,这里,就比较郁闷,要怎么反向?怎么反向?这只蚂蚁反向后又可能遇到另一只蚂蚁?中间那只蚂蚁是不是会被“打乒乓球”?思来想去很郁闷。那都是因为思维太窄了,为啥要精确到蚂蚁?哪只蚂蚁先掉下去对解题有影响吗?没有影响。所有的蚂蚁没有ABC之分,它只是蚂蚁,这只蚂蚁和那只蚂蚁也都只是蚂蚁而已,没有区别。这样,就感觉好多了,没那么复杂了。
两只蚂蚁相遇后,分别反向,继续走,由于两只蚂蚁没有区别,我们可以视为是两只蚂蚁相遇后“擦肩而过”。这样,思路就简单多了。对于每只蚂蚁来说,掉下竹竿的方式有2中,从竹竿的左边掉下去或从竹竿的右边掉下去。若是该蚂蚁初始位置离竹竿左边掉下点近,则从左边掉下去耗时最少,从右边掉下去耗时最多,否则反之。对于所有的蚂蚁来说,全部要掉下去,花的最短的时间就是所有蚂蚁都从离它初始位置最近的竹竿端掉下去花的时间(取耗时最长者,这样,所有的蚂蚁都在此蚂蚁掉下去之前掉下去了)。同理,花的最短的时间就是所有蚂蚁都从离它初始位置最远的竹竿端掉下去花的时间(取耗时最长者,这样,所有的蚂蚁都在此蚂蚁掉下去之前掉下去了)。
#include<stdio.h>
#include<algorithm>
using namespace std;
int main()
{
int t,l,n;
int x,r,i;
int cumin1,cumax1;
int min1,max1;
scanf("%d",&t);
while(t--)
{
min1=0;
max1=0;
scanf("%d%d",&l,&n);
for(i=0; i<n; i++)
{
scanf("%d",&x);
r=l-x; //求蚂蚁往右走,多久能掉下竹竿
if(r<x) swap(r,x);
max1=max(max1,r); //求所有蚂蚁掉下竹竿所需的最少时间(蚂蚁掉下的最少时间的最大值)
min1=max(min1,x); //求所有蚂蚁掉下竹竿所需的最多时间
}
printf("%d %d\n",min1,max1);
}
return 0;
}
B. Best Cow Line
FJ is about to take his N (1 ≤ N ≤ 2,000) cows to the annual"Farmer of the Year" competition. In this contest every farmer arranges his cows in a line and herds them past the judges.
The contest organizers adopted a new registration scheme this year: simply register the initial letter of every cow in the order they will appear (i.e., If FJ takes Bessie, Sylvia, and Dora in that order he just registers BSD). After the registration phase ends, every group is judged in increasing lexicographic order according to the string of the initials of the cows' names.
FJ is very busy this year and has to hurry back to his farm, so he wants to be judged as early as possible. He decides to rearrange his cows, who have already lined up, before registering them.
FJ marks a location for a new line of the competing cows. He then proceeds to marshal the cows from the old line to the new one by repeatedly sending either the first or last cow in the (remainder of the) original line to the end of the new line. When he's finished, FJ takes his cows for registration in this new order.
Given the initial order of his cows, determine the least lexicographic string of initials he can make this way.
Input
* Line 1: A single integer: N
* Lines 2..N+1: Line i+1 contains a single initial ('A'..'Z') of the cow in theith position in the original line
Output
The least lexicographic string he can make. Every line (except perhaps the last one) contains the initials of 80 cows ('A'..'Z') in the new line.
Sample Input
6
A
C
D
B
C
B
Sample Output
ABCBCD
解题思路:该题考字符串或者说是串的处理,主要是比较。
有一个人,有很多牛,没头牛有自己的名字,排成一排,现在要分别取出个头牛的名字的首字母排成字符串。检查时,根据首字母排成的字符串按字典先后顺序排序后一次检查(很多个人的牛参加检查)。这个人先尽快的检查完自己的牛,然后回家干农活。现在给出一个整数n表示他有n头牛,然后给出他的所有的牛的名字的首字母(按照从左到右的顺序输出),每个字母占一行。要求输出他的牛排序后的序列(名字的首字母序列),每80头牛的名字首字母占一行,最后一行除外。要求让这个人的牛尽早的参加检查。他只能从他的牛群现在的顺序的左端或右端(或时挑剩下的牛)取牛出来排到新的牛群的后面。
其实就是一个字符串的字典序前后情况的处理,如果现在留下的牛群的名字的首字的顺序比其逆序的字典序前,则取字符串的顺序第一个字母输出;否则,取其逆序第一个字母输出。
注意:1、输入时,每行输入一个字母,但是,前后可能有空格输入,使用scanf("%s",a);即可读取一个字母到地址a处,直接滤掉空格,接受到回车时结束输入。
2、输出时,当输出字符(该行)为80个时换行,最后也要换行(如果本行有字母输出)。
#include<stdio.h>
#include<string.h>
int main()
{
int n,i,j,k;
char cow[2005],cow1[2005],cow2[2005];
while(scanf("%d",&n)!=EOF)
{
for(i=0; i<n; i++)
scanf("%s",cow+i); //牛的名字的首字母读入,读入一个字符到地址cow+i处,自动滤掉空格
for(i=0; i<n; i++)
{
if(i!=0&&i%80==0) //若后面还有字母要输出,本行输出以及达到80个字母,则换行
printf("\n");
strcpy(cow1,cow); //将cow中内容拷贝到cow1中
int str=strlen(cow);
for(j=str-1,k=0; j>=0; j--,k++) //将cow1中内容逆序拷贝到cow2中
cow2[k]=cow1[j];
cow2[str]='\0';
if(strcmp(cow,cow2)<0) //比较cow和cow2的内容,即字符串的顺序和逆序的字典序情况,若cow排列靠前
{
printf("%c",cow[0]); //输出cow中顺序的第一个字母
for(j=0; j<=str; j++) //后面所有的字母都前移一位,包括字符结束标志
cow[j]=cow[j+1];
}
else //cow2字典序排列靠前
{
printf("%c",cow[str-1]); //输出cow中逆序第一个字母
cow[str-1]='\0'; //处理字符结束志,利于比较函数处理
}
} //知道n个字母全部处理完
printf("\n");
}
return 0;
}
C. 1sting
Input
Output
Sample Input
3
1
11
11111
Sample Output
1
2
8
解题思路:本题考大数计算,可用数组模拟,也可直接用JAVA中的BigInteger方法处理。
给出一个t,表示有t组测试数据。给出一个长度在200以内的1的串,要求出其由1化2的串的个数(两个1可化为1个2)。
对数据稍做处理后可发现,要输出的答案和1的序列的长度呈斐波那契数列的规律。设1序列的长度为i,要输出的结果的值为sum(i),则有:sum(1)=1,sum(2)=2,sum(i)=sum(i-1)+sum(i-2);直接用JAVA中大数方法BigInteger(个人测试,至少可以存储500位的十进制整数)处理即可。
import java.math.BigInteger;
import java.util.*;
public class Main
{
public static void main(String[] args)
{
Scanner as=new Scanner(System.in);
String s;
BigInteger[] sum=new BigInteger[205];
int t,i;
sum[1]=BigInteger.ONE;
sum[2]=BigInteger.valueOf(2);
for(i=3; i<=200; i++)
{
sum[i]=sum[i-1].add(sum[i-2]); //sum(i)=sum(i-1)+sum(i-2);
}
t=as.nextInt(); //输入测试数据组数
while(t-->0)
{
s=as.next();
System.out.println(sum[s.length()]); //直接输出sum[i]
}
}
}
D. Can you solve this equation?
Now please try your lucky.
Input
Output
Sample Input
2
100
-4
Sample Output
1.6152
No solution!
解题思路:本题考查数学函数基础性质和二分法。
给出一个t,表示测试数据组数。给出一个y,要求出方程式 8*x^4 + 7*x^3 + 2*x^2 + 3*x + 6 == Y的近似解,精确到小数点后四位。
对于输入的y,作两种情况讨论处理(1)对于x在[0,100]间无法求解的,直接输出“No solution!”即可。(2)对于x在(0,100)间有解的,直接用二分法(在区间中递增)求出近似解即可。
证明原方程在区间[0,100]是单调(递增或递减)的
证:设f(x)= 8*x^4 + 7*x^3 + 2*x^2 + 3*x + 6 - Y
要证明f(x)在区间[0,100]的单调性,只要f'(x)在[0,100]间都有f'(x)>0或f'(x)<0即可
f'(x)=32*x^3+21*x^2+4*x+3
由f'(x),可知,当x在区间[0,100]中时,x>0,则有f'(x)>0恒成立,即f(x)在区间[0,100]上是单调递增的。
#include<stdio.h>
#include<algorithm>
using namespace std;
int y;
double f(double x)
{
return 8*x*x*x*x+7*x*x*x+2*x*x+3*x+6-y;
}
double find(double x1,double x2)
{
double m;
while(x1<=x2)
{
if(x2-x1<0.000001)break;
m=(x1+x2)/2;
if(f(m)*f(x2)>0)
x2=m-0.0000001;
else
x1=m+0.0000001;
}
return x2;
}
int main()
{
int x,t;
int i,j;
scanf("%d",&t);
while(t--)
{
scanf("%d",&y);
if(f(0)*f(100)>0) printf("No solution!\n"); //在给定区间上无解
else printf("%.4lf\n",find(0,100)); //二分法求解,输出时保留4位小数
}
return 0;
}
E. Triangular Pastures
I. M. Hei, the lead cow pasture architect, is in charge of creating a triangular pasture surrounded by nice white fence rails. She is supplied with N (3 <= N <= 40) fence segments (each of integer length Li (1 <= Li <= 40) and must arrange them into a triangular pasture with the largest grazing area. Ms. Hei must use all the rails to create three sides of non-zero length.
Help Ms. Hei convince the rest of the herd that plenty of grazing land will be available.Calculate the largest area that may be enclosed with a supplied set of fence segments.
Input
* Lines 2..N+1: N lines, each with a single integer representing one fence segment's length. The lengths are not necessarily unique.
Output
Sample Input
5
1
1
3
3
4
Sample Output
692
Hint
[which is 100x the area of an equilateral triangle with side length 4]
解题思路:该题可用动态规划解答。
给出一个n,表示棍子的数量,给n根长度不一定相同的棍子的长度,用这些棍子拼接三角形(全部用上)。求拼出的三角形的最大的面积,输出面积乘以100后的值的整数部分。
用动态规划求解dp[i][j]表示用所有的棍子拼三角形时分别可以拼成一条长为i的和一条长为j的边,对于第k根木棍而言,(i=middle; i>=0; i--) (j=middle; j>=0; j--),若dp[i][j]=1,即前面的木棍能拼成i和j长度的边,则加入这根木棍后,可拼成的边的长度为(i,j+a[k])或(i+a[k],j)。则有,若dp[i][j]=1,则可推出dp[i][j+a[k]]=1,dp[i+a[k]][j]=1.由于三角形的变成有:两边之和大于第三边,所以,没天边的长度不会大于其周长的一半,所以搜索时只要最大只要搜到middle即可。动态规划处理后,可得出三角形的三边可以由哪些长度组成。而后,对真个dp数组进行查询对比,找出所给棍子能拼成的三角形的最大的面积,处理输出即可。
#include<stdio.h>
#include<math.h>
bool check(int x,int y,int z)
{
if(x+y>z&&x+z>y&&y+z>x) return true;
return false;
}
double cul(int x,int y,int z)
{
double m=(double)(x+y+z)/2;
return sqrt(m*(m-x)*(m-y)*(m-z));
}
int dp[800][800];
int main()
{
int n;
int str[40];
int max1,middle;
int i,j,k;
while(scanf("%d",&n)!=EOF)
{
max1=0;
double max2=0;
for(i=0; i<n; i++)
scanf("%d",&str[i]),max1+=str[i];
middle=max1/2;
dp[0][0]=1;
for(k=0; k<n; k++)
{
for(i=middle; i>=0; i--)
{
for(j=middle; j>=0; j--)
{
if(dp[i][j])
{
dp[i][j+str[k]]=1; //加入第k根木棍后,可拼成的边的长度为(i,j+a[k])或(i+a[k],j)
dp[i+str[k]][j]=1;
}
}
}
}
for(i=1; i<=middle; i++)
{
for(j=1; j<=middle; j++)
{
if(dp[i][j]) //木棍能拼成i和j长度的边
{
int m=max1-i-j;
if(check(i,j,m)) //若三边能构成三角形
{
double x=cul(i,j,m); //求该三角形的面积
if(x>max2) max2=x; //记录最大值
}
}
}
}
if(max2>0)printf("%d\n",(int)(max2*100));
else printf("-1\n");
}
return 0;
}