Square
Description
It was the first time that our government organized the 2015 ACM PCPC (Paper Cutting Programming Contest) in Bangkok last week. The objective of this event is to create a relationship between computer students in ASEAN. More than thousands of students applied to this PCPC. Eventually, there were M matches running on the final round. This is the regulation of the contest:
Match between Two Teams
Material: One piece of rectangle paper with dimension L” × W”.
Mission of each player:
Cut the paper into possible largest squares and pass the remainder to the next player. For each of the rounds, player must cut 1 or more squares, all squares must have the same size. The condition for the remainder is to be a single piece of rectangle.
The winner: the player who cuts the paper without the remainder.
The record of the game is W L r a1 a2 … ar
Where L : length of the original rectangle paper
W : width of the original rectangle paper
ai : the number of squares in ith-turn.
r : the number of turns for this game
Example:
A square paper size 5” × 2”.
The first player can cut 2 squares of 2” × 2”. The remainder is therefore a rectangle 2” × 1”.
The second player can cut 2 squares with 1” × 1” without the remainder.
The record of this game is 5 2 2 2 2
Because of the error of the computer system, the memory is magically disappeared. Only two first numbers of each record cannot be read. Our mission is to find only the first number. In the case that there are more than one possible value, we take only the smallest length.
Limitation:
1 <= M <= 20
1 <= W, L <= 10100
1 <= r <= 50
1 <= ai <= 100
Input
The input contains M + 1 lines
The first line contains one integer M
The M next lines contain r+1 integers
The first integer is r
The next r integers are ai where 1 ≤ I ≤ r
Output
The output contains M lines where each line contains one integer L (the longer size of the rectangle).
Sample Input
2
2 2 2
3 1 1 4
Sample Output
5
9
Hint
Source
ACM-ICPC Asia Thailand National On-Site Programming Contest 2015
题意:有一个L×W的矩形,然后每次轮到一个人就将这个矩形中的最大的正方形给拿掉,然后至少拿掉一个,每个正方形的大小一样,当最后一个人能将矩形拿完就是胜利者。比如2×5的矩形,第一个人拿掉2个2×2的正方形,然后剩下1×2的矩形,这个人就可以拿掉2个1×1的正方形,然后赢了,然后就有5 2 2 2 2,表示5*2的矩形,然后有2个人参与,分别拿掉2 个正方形。现在,给出参与的人数r,还有r个人按顺序拿掉的数目ai,然后要我们求出原来的矩形中的较长边的长度,然后这条边的长度要最小。
分析:由题意可以知道要使最后的答案尽可能的小,最后拿的人所拿掉的应该都为1*1的正方形,然后倒数第二个人拿掉的应该是在最后一个人中长的边为正方形的长,因为如果为短的边,此时这个人就可以直接将所有的正方形拿完了。比如第一个样例中的2 2 2,最后一个人拿掉了2个正方形,所以这个人拿之前剩下的矩形为1*2,然后可以知道第一个人拿掉的正方形的边长为2,因为如果为1的话,这个人可以直接把所有的1*1的正方形拿掉。所以就可以得到第一个人拿之前矩形为2*5,所以答案为5,所以可以得到推导公式L=L*a[i]+W,L为当前矩形中较长的边,W为但前矩形中较短的边。只要从后往前遍历一遍就能得出答案了。但题目中提到了L和W的范围为10^100明显超出了long long 的范围,所以得用到高精度,然后可以用c++求解,同样也可以用java求解。
代码:
/*
* 高精度,支持乘法和加法
*/
#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<vector>
#include<math.h>
#include<map>
#include<queue>
#include<algorithm>
using namespace std;
const int inf = 0x3f3f3f3f;
struct BigInt{
const static int mod=10000;
const static int DLEN=4;
int a[600],len;
BigInt(){
memset (a,0,sizeof (a));
len=1;
}
BigInt(int v){
memset (a,0,sizeof (a));
len=0;
do{
a[len++]=v%mod;
v/=mod;
} while (v);
}
BigInt(const char s[]){
memset (a,0,sizeof (a));
int L=strlen (s);
len=L/DLEN;
if (L%DLEN)len++;
int index=0;
for (int i=L-1;i>=0;i-=DLEN){
int t=0;
int k=i-DLEN+1;
if (k<0)k=0;
for (int j=k;j<=i;j++){
t=t*10+s[j]-'0';
}
a[index]=t;
}
}
BigInt operator +(const BigInt &b)const {
BigInt res;
res.len=max(len,b.len);
for (int i=0;i<=res.len;i++){
res.a[i]=0;
}
for (int i=0;i<res.len;i++){
res.a[i]+=((i<len)?a[i]:0)+((i<b.len)?b.a[i]:0);
res.a[i+1]+=res.a[i]/mod;
res.a[i]%=mod;
}
if (res.a[res.len]>0)res.len++;
return res;
}
BigInt operator *(const BigInt &b)const {
BigInt res;
for (int i=0;i<len;i++){
int up=0;
for (int j=0;j<b.len;j++){
int tmp=a[i]*b.a[j]+res.a[i+j]+up;
res.a[i+j]=tmp%mod;
up=tmp/mod;
}
if (up!=0){
res.a[i+b.len]=up;
}
}
res.len=len+b.len;
while (res.a[res.len-1]==0&&res.len>1)res.len--;
return res;
}
void output(){
printf ("%d",a[len-1]);
for (int i=len-2;i>=0;i--){
printf ("%04d",a[i]);
}
printf ("\n");
}
};
int a[55];
int main ()
{
int t;
scanf ("%d",&t);
while (t--){
int r;
scanf ("%d",&r);
for (int i=1;i<=r;i++){
scanf ("%d",&a[i]);
}
BigInt L=BigInt(a[r]);
BigInt W=BigInt(1);
for (int i=r-1;i>=1;i--){
BigInt t=L;//先保存L
L=L*a[i]+W;
W=t; //赋给W
}
L.output();
}
return 0;
}
除了用c++求解之外,还可以用java求解,用java中的大整数类可以求解,第一次写java的大数类,有点丑。。。
代码:
import java.math.*;
import java.util.Scanner;
public class Main {
public static void main(String []args){
BigInteger L,W;
Scanner cin=new Scanner(System.in);//输入
int t=cin.nextInt();
int r;
BigInteger[] a=new BigInteger[55];//定义出现的数目,直接定义大整数类,方便后面的计算
while (t!=0){
t--;
r=cin.nextInt();
for (int i=1;i<=r;i++){
a[i]=cin.nextBigInteger();
}
L=a[r];
W=new BigInteger("1");
for (int i=r-1;i>=1;i--){
BigInteger tmp=L;
L=L.multiply(a[i]);//先乘
L=L.add(W);//再加
W=tmp;
}
System.out.println(L);//输出
}
}
}