灵动ICPC冬令营基础-3

A - Birthday Cake

题目

在这里插入图片描述
Lucy and Lily are twins. Today is their birthday. Mother buys a birthday cake for them. Now we put the cake onto a Descartes coordinate. Its center is at (0, 0), and the cake’s length of radius is 100.
There are 2N (N is a integer, 1 ≤ N ≤ 50) cherries on the cake. Mother wants to cut the cake into two halves with a knife (of course a beeline). The twins would like to be treated fairly, that means, the shape of the two halves must be the same (that means the beeline must go through the center of the cake) , and each half must have N cherrie(s). Can you help her?
Note: the coordinate of a cherry (x, y) are two integers. You must give the line as form two integers A, B (stands for Ax + By = 0) each number mustn’t in [−500, 500]. Cherries are not allowed lying on the beeline. For each dataset there is at least one solution.
Input
The input file contains several scenarios. Each of them consists of 2 parts: The first part consists of a line with a number N, the second part consists of 2N lines, each line has two number, meaning (x, y). There is only one space between two border numbers. The input file is ended with N = 0.
Output
For each scenario, print a line containing two numbers A and B. There should be a space between
them. If there are many solutions, you can only print one of them.
Sample Input

2
-20 20
-30 20
-10 -50
10 -5
0

Sample Output

0 1

解析

本题的第一行输入N,表示蛋糕上有2N个樱桃。接下来的2N行每行给出一个樱桃的坐标,因为蛋糕是一个原点为圆心,半径为100的圆,所以坐标值的范围是[-100, 100]。本题的输出是一个直线方程Ax+By=0的A和B,范围是[-500, 500]。本题采取枚举方法,在[-500, 500]的范围内枚举A和B,将樱桃坐标代入直线方程Ax+By,如果Ax+By大于0,则樱桃在直线上方;小于0,则樱桃在直线下方;等于0,则不允许,因为樱桃不能在直线上。枚举直至产生第一个解。
注意:一定要考虑题意中N的存在性,以及直线的存在性;整理出计算思路,特性关系枚举正解。

代码

#include <cstdio>
const int N = 500;
struct Cord{
    
    
	int x, y;
}p[N];
int main() {
    
    
	int num, i, j, n, s, t, A, B, q;
	while(scanf("%d", &num)&&num) {
    
    
		for(i=1;i<=2*num;i++) {
    
    
		scanf("%d%d", &p[i].x, &p[i].y);
	}
	for(i=-N;i<=N;i++) {
    
    
		for(j=-N;j<=N;j++) {
    
    
			n=0, s=0, q=0;
			if(i*j==0) continue;
			for(t=1;t<=2*num;t++) {
    
    
				if(p[t].x>100||p[t].x<-100||p[t].y>100||p[t].y<-100) continue;
				else if(p[t].x*i+p[t].y*j>0) n++;
				else if(p[t].x*i+p[t].y*j<0) s++;
				else if(p[t].x*i+p[t].y*j==0) break;
			}
			if(n==s&&n+s==2*num) {
    
    
				A=i, B=j;
				q=1;
				break;
			}
		}
		if(q==1) break;
	}
	printf("%d %d\n", A, B);
	}
    return 0;
}

B - Is This Integration ?

题目

在这里插入图片描述

In the image below you can see a square ABCD, where AB = BC = CD = DA = a. Four arcs are drawn taking the four vertexes A, B, C, D as centers and a as the radius. The arc that is drawn taking A as center, starts at neighboring vertex B and ends at neighboring vertex D. All other arcs are drawn in a similar fashion. Regions of three different shapes are created in this fashion. You will have to determine the total area if these different shaped regions.
Input
The input file contains a floating-point number a (0 ≤ a ≤ 10000) in each line which indicates the length of one side of the square. Input is terminated by end of file.
Output
For each line of input, output in a single line the total area of the three types of region (filled with different patterns in the image above). These three numbers will of course be floating point numbers with three digits after the decimal point. First number will denote the area of the striped region, the second number will denote the total area of the dotted regions and the third number will denote the area of the rest of the regions.
Sample Input

0.1
0.2
0.3

Sample Output

0.003 0.005 0.002
0.013 0.020 0.007
0.028 0.046 0.016

解析

• 本题给出正方形的边长a,要求计算三种不同阴影部分的总面积。
如图所示,做辅助线画一等边三角形,并且三种不同阴影部分的
面积分别用x, y和z表示。
在这里插入图片描述
在这里插入图片描述
注意:此题主要考面积计算思路,整体化思想与个体化思想结合构建三元一次不等式求出各种面积表达式,最终转化为代码。

代码

#include <cstdio>
#include <cmath>
double a;
const double pi=acos(-1.0);
int main() {
    
    
	double x, y, z;
    while (scanf("%lf", &a)!=EOF) {
    
    
    	x=(1-sqrt(3.0)+pi/3)*a*a;
    	y=((-4+sqrt(3.0)*2)+pi/3)*a*a;
    	z=4*a*a-a*a*sqrt(3.0)-2*a*a*pi/3;
		printf("%.3lf %.3lf %.3lf\n", x, y, z);
	}
    return 0;
}

C - Simple division

题目

在这里插入图片描述

Integer division between a dividend n and a divisor d yields a quotient q and a remainder r. q is the integer which maximizes q ∗ d
such that q ∗ d ≤ n and r = n − q ∗ d.
For any set of integers there is an integer d such that each of the
given integers when divided by d leaves the same remainder.
Input
Each line of input contains a sequence of nonzero integer numbers separated by a space. The last number on each line is 0 and this number does not belong to the sequence. There will be at least 2 and no more than 1000 numbers in a sequence; not all numbers occuring in a sequence are equal. The last line of input contains a single 0 and this line should not be processed.
Output
For each line of input, output the largest integer which when divided into each of the input integers
leaves the same remainder.
Sample Input

701 1059 1417 2312 0
14 23 17 32 122 0
14 -22 17 -31 -124 0
0

Sample Output

179
3
3

解析

主要考察欧几里算法的应用
先求出原序列的一阶差分序列,然后求出所有非零元素的gcd即可。

代码

#include <cstdio>
int gcd(int a, int b) {
    
    
	return b==0?a:gcd(b, a%b);
}
int abs(int x) {
    
    
	return x>0?x:-x;
}
int a[1005];
int ans;
int main() {
    
    
	while (1) {
    
    
		int i=0, j;
		scanf("%d", &a[++i]);
		if(a[i]==0) break;
		while(a[i]!=0) scanf("%d", &a[++i]);
		i--;
		for (j=1;j<i;j++) {
    
    
			a[j]-=a[j+1];
		}
		ans=a[1];
		for (j=2;j<i;j++)
			ans=gcd(a[j]==0?ans:a[j], ans);
		printf("%d\n", abs(ans));
	}
	return 0;
}

D - Euclid Problem

题目

From Euclid it is known that for any positive integers A and B there exist such integers X and Y that AX + BY = D, where D is the greatest common divisor of A and B. The problem is to find for given A and B corresponding X, Y and D.
Input
The input will consist of a set of lines with the integer numbers A and B, separated with space (A, B < 1000000001).
Output
For each input line the output line should consist of three integers X, Y and D, separated with space. If there are several such X and Y , you should output that pair for which |X| + |Y | is the minimal. If there are several X and Y satisfying the minimal criteria, output the pair for which X ≤ Y .
Sample Input

4 6
17 17

Sample Output

-1 1 2
0 1 17

解析

在这里插入图片描述
扩展的欧几里得算法如下。

int exgcd(int a, int b, int &x, int &y) {
	if (b==0) {x=1; y=0; return a;}
	int t=exgcd(b, a%b, x, y);
	int x0=x, y0=y;
	x=y0; y=x0-(a/b)*y0;
	return t; 
}

代码

#include <cstdio>
int exgcd(int a, int b, int &x, int &y) {
    
    
	if (b==0) {
    
    x=1; y=0; return a;}
	int t=exgcd(b, a%b, x, y);
	int x0=x, y0=y;
	x=y0; y=x0-(a/b)*y0;
	return t;
}
int main() {
    
    
	int a, b, d, x, y;
	while(scanf("%d%d", &a, &b)!=EOF) {
    
    
		d=exgcd(a, b, x, y);
		printf("%d %d %d\n", x, y, d);
	}
	return 0;
}

E - Dead Fraction

题目

Mike is frantically scrambling to finish his thesis at the last minute. He needs to assemble all his research notes into vaguely coherent form in the next 3 days. Unfortunately, he notices that he had been extremely sloppy in his calculations. Whenever he needed to perform arithmetic, he just plugged it into a calculator and scribbled down as much of the answer as he felt was relevant. Whenever a repeating fraction was displayed, Mike simply reccorded the first few digits followed by “…”. For instance, instead of “1/3” he might have written down “0.3333…”. Unfortunately, his results require exact fractions! He doesn’t have time to redo every calculation, so he needs you to write a program (and FAST!) to automatically deduce the original fractions.
To make this tenable, he assumes that the original fraction is always the simplest one that produces the given sequence of digits; by simplest, he means the the one with smallest denominator. Also, he assumes that he did not neglect to write down important digits; no digit from the repeating portion of the decimal expansion was left unrecorded (even if this repeating portion was all zeroes).
Input
There are several test cases. For each test case there is one line of input of the form “0.dddd…” where dddd is a string of 1 to 9 digits, not all zero. A line containing 0 follows the last case.
Output
For each case, output the original fraction.
Sample Input

0.2...
0.20...
0.474612399...
0

Sample Output

2/9
1/5
1186531/2500000

Hint
Note that an exact decimal fraction has two repeating expansions (e.g. 1/5 = 0.2000… = 0.19999…).

解析

任何一个bai有理数都可以写成分数m/n(m,n都是整数,且n≠0)的形式。 证明……
无限循环小数转分数(0.xxxxx…)
小数部分 n位
循环部分 a位
非循环部分 (n-a)位
①分子为:n*10^n - n/10^a
②分母为:(10^(a)-1) * (10^(n-a))
最后通过 gcd()化简为最简分数
因为不确定循环节的部分,所以要枚举所有情况。 按题目要求输出分母最小的结果。

代码

#include <cstdio>
#include <cstring>
long int Tpow[10];
long int gcd(long int a, long int b) {
    
    
    if(b==0) return a;
    else return gcd(b,a%b);
}
void init() {
    
    
    int i;
    Tpow[0]=1;
    for(i=1;i<10;i++) {
    
    
        Tpow[i]=Tpow[i-1]*10;
    }
}
int main() {
    
    
    char s[200];
    long int ans,a,b,c, temp, mina, minb,t, i;
    init();
    while(~scanf("%s",s)) {
    
    
        if(s[0]=='0'&&strlen(s)==1) break;
        ans=0;
        t=0;
        mina=-1;minb=-1;
        for(i=2;s[i]!='.';i++) {
    
    
            ans=ans*10+s[i]-'0';
            t++;
        }
        for(i=t;i>0;i--) {
    
    
            c=ans;
            b=Tpow[t-i]*(Tpow[i]-1);
            c=c/Tpow[i];
            a=ans-c;
            temp=gcd(a,b);
            if(b/temp<minb||mina==-1) {
    
    
                mina=a/temp;
                minb=b/temp;
            }
    	}
		printf("%d/%d\n",mina,minb);
   }
   return 0;
}

F - What is the Probability ?

题目

Probability has always been an integrated part of computer algorithms. Where the deterministic algorithms have failed to solve a problem in short time, probabilistic algorithms have come to the rescue. In this problem we are not dealing with any probabilistic algorithm. We will just try to determine the winning probability of a certain player. A game is played by throwing a dice like thing (it should not be assumed that it has six sides like an ordinary dice). If a certain event occurs when a player throws the dice (such as getting a 3, getting green side on top or whatever) he is declared the winner. There can be N such player. So the first player will throw the dice, then the second and at last the N-th player and again the first player and so on. When a player gets the desired event he or she is declared winner and playing stops. You will have to determine the winning probability of one (The I-th) of these players.
Input
Input will contain an integer S (S ≤ 1000) at first, which indicates how many sets of inputs are there. The next S lines will contain S sets of inputs. Each line contain an integer N (N ≤ 1000) which denotes the number players, a floating point number p which indicates the probability of the happening of a successful event in a single throw (If success means getting 3 then p is the probability of getting 3 in a single throw. For a normal dice the probability of getting 3 is 1/6), and I (I ≤ N) the serial of the player whose winning probability is to be determined (Serial no varies from 1 to N). You can assume that no invalid probability § value will be given as input.
Output
For each set of input, output in a single line the probability of the I-th player to win. The output floating point number will always have four digits after the decimal point as shown in the sample output.
Sample Input

2
2 0.166666 1
2 0.166666 2

Sample Output

0.5455
0.4545

解析

在这里插入图片描述

代码

#include <cstdio>
#include <cmath>
int main() {
    
    
	int s, n, i, j;
	double p, w;
	scanf("%d", &s);
	while(s--) {
    
    
		scanf("%d %lf %d", &n, &p, &i);
		if(p==0) printf("0.0000\n");
		else {
    
    
			w=(pow(1-p, i-1)*p)/(1-pow(1-p, n));
			printf("%.4lf\n", w);
		}
	}
	return 0;
}

G - Burger

题目

When Mr. and Mrs. Clinton’s twin sons Ben and Bill had their tenth birthday, the party was held at the McDonald’s restaurant at South Broadway 202, New York. There were 20 kids at the party, including Ben and Bill. Ronald McDonald had made 10 hamburgers and 10 cheeseburgers and when he served the kids he started with the girl directly sitting left of Bill. Ben was sitting to the right of Bill. Ronald flipped a (fair) coin to decide if the girl should have a hamburger or a cheeseburger, head for hamburger, tail for cheeseburger. He repeated this procedure with all the other 17 kids before serving Ben and Bill last. Though, when coming to Ben he didn’t have to flip the coin anymore because there were no cheeseburgers left, only 2 hamburgers. Ronald McDonald was quite surprised this happened, so he would like to know what the probability is of this kind of events. Calculate the probability that Ben and Bill will get the same type of burger using the procedure described above. Ronald McDonald always grills the same number of hamburgers and cheeseburgers.
Input
The first line of the input-file contains the number of problems n , followed by n times: a line with an even number [2,4,6,…,100000], which indicates the number of guests present at the party including Ben and Bill.
Output
The output consists of n lines with on each line the probability (4 decimals precise) that Ben and Bill get the same type of burger. Note: a variance of ±0.0001 is allowed in the output due to rounding differences.
Sample Input

3
6
10
256

Sample Output

0.6250
0.7266
0.9500

解析

在这里插入图片描述
假设Ben和Bill拿到了不同的汉堡,然后前面2i-2个人中先分配汉堡一共Ci-22i-2种排法,每个排法实现都是1/2的概率所以最终有Ci-22i-2/22i-2的概率。
本题要考虑一下运行的次数,要么优化代码缩小运行次数避免超时,要么运用离线计算。

代码

减少运行次数

#include <cstdio>
#include <cmath>
const int N=50008;
double p[N];
double pw(int n) {
    
    
	int i;
	p[1]=1;
    for(i=1;i<=n/2-1;i++)//i<=n/2-1实现了一次减少范围
        p[i+1]=1.*(2*i-1)*p[i]/(double)(2*i);
    return p[n/2];
}
int main() {
    
    
	int n, num;
	scanf("%d", &n);
	while(n--) {
    
    
		scanf("%d", &num);
		printf("%.4lf\n", 1-pw(num));
	}
	return 0;
}

离线计算

#include <iostream>
#include <cstdio>
using namespace std;
const int N = 5e4+7;
int cas,n;
double p[N];
void solve(){
    
    
	p[1] = 1;
	for(int i = 1; i < 5e4; ++i)
		p[i+1] = (2*i-1)*p[i]/(2*i);
}
int main() {
    
    
	cin>>cas;
	solve();
	while(cas--){
    
    
		cin>>n;
		n /= 2;
		printf("%.4lf\n",1-p[n]);
	}
	return 0;
}

H - Coin Toss

题目

In a popular carnival game, a coin is tossed onto a table with an area that is covered with square tiles in a grid. The prizes are determined by the number of tiles covered by the coin when it comes to rest: the more tiles it covers, the better the prize. In the following diagram, the results from five coin tosses are shown:

在这里插入图片描述

In this example:

coin 1 covers 1 tile
coin 2 covers 2 tiles
coin 3 covers 3 tiles
coin 4 covers 4 tiles
coin 5 covers 2 tiles
Notice that it is acceptable for a coin to land on the boundary of the playing area (coin 5). In order for a coin to cover a tile, the coin must cover up a positive area of the tile. In other words, it is not enough to simply touch the boundary of the tile. The center of the coin may be at any point of the playing area with uniform probability. You may assume that (1) the coin always comes to a rest lying flat, and (2) the player is good enough to guarantee that the center of the coin will always come to rest on the playing area (or the boundary).

The probability of a coin covering a certain number of tiles depends on the tile and coin sizes, as well as the number of rows and columns of tiles in the playing area. In this problem, you will be required to write a program which computes the probabilities of a coin covering a certain number of tiles.

Input
The first line of input is an integer specifying the number of cases to follow. For each case, you will be given 4 integers m, n, t, and c on a single line, separated by spaces. The playing area consists of m rows and n columns of tiles, each having side length t. The diameter of the coin used is c. You may assume that 1 <= m, n <= 5000, and 1 <= c < t <= 1000.
Output
For each case, print the case number on its own line. This is followed by the probability of a coin covering 1 tile, 2 tiles, 3 tiles, and 4 tiles each on its own line. The probability should be expressed as a percentage rounded to 4 decimal places. Use the format as specified in the sample output. You should use double-precision floating-point numbers to perform the calculations. “Negative zeros” should be printed without the negative sign.

Separate the output of consecutive cases by a blank line.
Sample Input

3
5 5 10 3
7 4 25 20
10 10 10 4

Sample Output

Case 1:
Probability of covering 1 tile  = 57.7600%
Probability of covering 2 tiles = 36.4800%
Probability of covering 3 tiles = 1.2361%
Probability of covering 4 tiles = 4.5239%

Case 2:
Probability of covering 1 tile  = 12.5714%
Probability of covering 2 tiles = 46.2857%
Probability of covering 3 tiles = 8.8293%
Probability of covering 4 tiles = 32.3135%

Case 3:
Probability of covering 1 tile  = 40.9600%
Probability of covering 2 tiles = 46.0800%
Probability of covering 3 tiles = 2.7812%
Probability of covering 4 tiles = 10.1788%

解析

对于本题,因为硬币的圆心可以在网格区域中的任何一点,概率都是一样的,所以我们将硬币视为圆心一点,考虑硬币的圆心位置与硬币所盖到的方砖数目的关系,计算硬币盖到不同数目方砖的情况的面积。而硬币盖到不同数目方砖的情况,如上图所示。硬币盖到2块方砖,如上图的硬币2和硬币5,有两种情况:
(1)硬币2的情况,对于网格区域的每条两个方砖相接的内部边界线,硬币要在这些边界线上,但不能在边界线的两端和其他方砖相接。内部纵向边界 线有m(n-1)条,内部横向边界线有n(m-1)条,所以,一共有2mn-n-m条内部边界线。对于每条内部边界线,硬币能够盖到2个方格,其圆心所能在的位置的面积为c * (t - c);因此,硬币的圆心所能在的位置的面积为c * (t - c) * (2 * m * n - n - m)。
(2)硬币5的情况,硬币覆盖两个边界方砖和网格边界线,两个边界方砖和网格边界线的交点一共有2 * n + 2 * m – 4个;对于每个交点,硬币的圆心能在的位置所覆盖的面积为c * (c / 2);因此,硬币的圆心所能在的位置的面积为c*(c/2)(2n+2m-4)。硬币盖到3块方砖或4块方砖,如上图的硬币3和硬币4的情况,在网格区域中,一共有(m-1)(n-1)个内部交叉点,所以有(m-1)(n-1)个区域可以放置硬币,而每个区域的硬币的圆心能在的位置所覆盖的面积为c2。当交叉点到硬币圆心的距离小于硬币半径时,硬币盖到4块方砖,硬币的圆心能在的位置所覆盖的面积是c2/4。所以,硬币盖到4块方砖,其圆心所在的位置的总面积是(m-1)(n-1)* c2/4;而硬币盖到3块方砖的总面积是(m-1)(n-1)c2-(m-1)(n- 1) c2/4。硬币盖到1块方砖的面积,是网格的总面积(n * m * t2)减去硬币盖到2块方砖、3块方砖和4块方砖的面积。 由此,根据1枚硬币盖到1块、2块、3块和4块方砖时,其圆心所在位置覆盖的面积为分子,网格的总面积为分母,计算1枚硬币盖到1块、2块、3块和4块方砖的概率。此外,由于c<t,本题不用考虑“负零(Negative zeros)”的情况;所谓负零,是指当一个浮点数运算产生了一个无限接近0并且没有办法正常表示出来的负浮点数,就产生负零。如果要考虑负零,则如参考程序所示,在计算1枚硬币盖到1块方砖,其圆心所在位置覆盖的面积s1之后,加一句“s1 = max(s1, 0.0);”。

代码

#include <cstdio>
#include <cmath>
using namespace std;
const double PI = acos(-1.0);
int main() {
    
    
    double m, n, c, t, sum, s1, s2, s3, s4;
    int T, i;
    scanf("%d", &T);
    for(i=1;i<=T;i++) {
    
    
        scanf("%lf%lf%lf%lf", &m, &n, &t, &c);
		sum=n*m*t*t;
        s2=c*(t-c)*(2*m*n-n-m)+c*(c/2)*(2*n+2*m-4);
        s4=PI*c*c/4.0*(m-1)*(n-1);
        s3=(m-1)*(n-1)*c*c-s4;
        s1=sum-s2-s3-s4;
        printf("Case %d:\n", i);
        printf("Probability of covering 1 tile  = %.4f%%\n", s1/sum*100);
        printf("Probability of covering 2 tiles = %.4f%%\n", s2/sum*100);
        printf("Probability of covering 3 tiles = %.4f%%\n", s3/sum*100);
        printf("Probability of covering 4 tiles = %.4f%%\n", s4/sum*100);
        if(i!=T) puts("");
    }
    return 0;
}

I - 498-bis

题目

Looking throw the “Online Judge’s Problem Set Archive” I found a very interesting problem number 498, titled “Polly the Polynomial”. Frankly speaking, I did not solve it, but I derived from it this problem.Everything in this problem is a derivative of something from 498. In particular, 498 was “… designedto help you remember … basic algebra skills, make the world a better place, etc., etc.”. This problemis designed to help you remember basic derivation algebra skills, increase the speed in which worldbecomes a better place, etc., etc.In 498 you had to evaluate the values of polynomial a0xn + a1xn−1 + . . . + an−1x + an.In this problem you should evaluate its derivative. Remember that derivative is defined as a0nxn−1 + a1(n − 1)xn−2+ . . . + an−1.All the input and output data will fit into integer, i.e. its absolute value will be less than 231.
Input
Your program should accept an even number of lines of text. Each pair of lines will represent one problem. The first line will contain one integer - a value for x. The second line will contain a list ofintegers a0, a1, …, an−1, an, which represent a set of polynomial coefficients. Input is terminated by !EOF.
Output
For each pair of lines, your program should evaluate the derivative of polynomial for the given value x and output it in a single line.
Sample Input

7
1 -1
2
1 1 1

Sample Output

1
5

解析

解决输入问题:
本题的多项式项数是不定的,并且未给出上限,所以不适合用数组保存。
所以考虑以下的一种输入方式。
因为所给的多项式的次数是从高到低排列的,所以可以将整个多项式分成 n个阶段。
第 i+1个阶段可以由第 i个阶段来表示。
具体的递推式为A(i+1)=A(i)*x+ai
如下图,每行就是一个阶段。

下面来考虑我们的求导方法:
在上述求整个多项式的过程中,递推求导,变量迭代。
关注递推:
后一阶段的导数由前一阶段的导数和原函数组成,想一想为什么?
后一阶段相对于前一个阶段,多乘了一个x ,所以其导数就比前一阶段在系数上要多1后一阶段的导数相对于前一阶段多了一个常数
这些多出来的部分就是前一阶段的原函数。

代码

#include <cstdio>
#include <cmath>
int main() {
    
    
	int x, a, sum, ans;
	char c;
	while(scanf("%d", &x)!=EOF) {
    
    
		sum=0, ans=0;
		while(scanf("%d", &a)!=EOF) {
    
    
			ans=ans*x+sum;
			sum=sum*x+a;
			scanf("%c", &c);
			if(c=='\n') break;
		}
		printf("%d\n", ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_52328032/article/details/112901326