第八周周赛——复习题解(出自codeforces 633A,610A,poj2155,poj3070,codeforces 538B,codeforces 513A)

A题:

A题题目链接

题目描述:

Ebony and Ivory

TimeLimit:2000MS  MemoryLimit:256MB
64-bit integer IO format: %I64d

Problem Description

Dante is engaged in a fight with "The Savior". Before he can fight it with his sword, he needs to break its shields. He has two guns, Ebony and Ivory, each of them is able to perform any non-negative number of shots.

For every bullet that hits the shield, Ebony deals a units of damage while Ivory deals b units of damage. In order to break the shield Dante has to deal exactly c units of damage. Find out if this is possible.

Input

The first line of the input contains three integers abc (1 ≤ a, b ≤ 100, 1 ≤ c ≤ 10 000) — the number of units of damage dealt by Ebony gun and Ivory gun, and the total number of damage required to break the shield, respectively.

Output

Print "Yes" (without quotes) if Dante can deal exactly c damage to the shield and "No" (without quotes) otherwise.

SampleInput 1
4 6 15
SampleOutput 1
No
SampleInput 2
3 2 7
SampleOutput 2
Yes
SampleInput 3
6 11 6
SampleOutput 3
Yes
 
    
Note

In the second sample, Dante can fire 1 bullet from Ebony and 2 from Ivory to deal exactly 1·3 + 2·2 = 7 damage. In the third sample, Dante can fire 1 bullet from ebony and no bullets from ivory to do 1·6 + 0·11 = 6 damage.

题意:

给定三个数a,b,c,判断是否存在两个数i * a + j * b = c(i,j均是大于等于0的整数),如果存在的话,则输出Yes;否则的话,输出No.

解析:

首先我们看a,b,c的范围(1 ≤ a, b ≤ 100, 1 ≤ c ≤ 10 000),在极限的情况下,为1 1 10000,因此我们可以确定a,b的范围,均为小于

等于5000的数字,所以最坏的时间复杂度为5000*5000,即为2.5*10^7,而题目的时限为2000ms,因此暴力枚举是可以通过的。

完整代码实现:

#include
int main(){
    int a,b,c;
    while(scanf("%d %d %d",&a,&b,&c)==3){
        bool tmp = false;
        for(int i = 0;i < 5005;++i){
            for(int j = 0;j < 5005;++j){
                if(i*a+j*b==c){
                    puts("Yes");
                    tmp = true;
                    break;
                }
            }
            if(tmp){
                break;
            }
        }
        if(!tmp){
            puts("No");
        }
    }
}

其实这道题一层for循环暴力遍历即可,因此改进后的代码为(来自苏程恺学长):

#include
#include
using namespace std;
int main()
{
    int a,b,c;
    while(scanf("%d%d%d",&a,&b,&c)!=EOF)
    {
        int temp=1;
        for(int i=0;i*(a+b)<=c;i++)
        {
            int k=c-(a+b)*i;
            if(k%a==0)
            {
                temp=0;
                printf("Yes\n");
                break;
            }
            if(k%b==0)
            {
                temp=0;
                printf("Yes\n");
                break;
            }
        }
        if(temp)printf("No\n");
    }
    return 0;
}
B题:

B题题目链接

题目描述:

Pasha and Stick

TimeLimit:1000MS  MemoryLimit:256MB
64-bit integer IO format: %I64d

Problem Description

Pasha has a wooden stick of some positive integer length n. He wants to perform exactly three cuts to get four parts of the stick. Each part must have some positive integer length and the sum of these lengths will obviously be n.

Pasha likes rectangles but hates squares, so he wonders, how many ways are there to split a stick into four parts so that it's possible to form a rectangle using these parts, but is impossible to form a square.

Your task is to help Pasha and count the number of such ways. Two ways to cut the stick are considered distinct if there exists some integer x, such that the number of parts of length x in the first way differ from the number of parts of length xin the second way.

Input

The first line of the input contains a positive integer n (1 ≤ n ≤ 2·109) — the length of Pasha's stick.

Output

The output should contain a single integer — the number of ways to split Pasha's stick into four parts of positive integer length so that it's possible to make a rectangle by connecting the ends of these parts, but is impossible to form a square.

SampleInput 1
6
SampleOutput 1
1
SampleInput 2
20
SampleOutput 2
4
 
    
Note

There is only one way to divide the stick in the first sample {1, 1, 2, 2}.

Four ways to divide the stick in the second sample are {1, 1, 9, 9}, {2, 2, 8, 8}, {3, 3, 7, 7} and {4, 4, 6, 6}. Note that {5, 5, 5, 5} doesn't work.

题意:

给定一个整数,作为一个矩形的周长,求能够构成多少种非正方形的矩形。

解析:

由于矩形的周长公式为 C = 2 * (a + b),因此给定的整数必须要为偶数,否则的话则不可能作为一个矩形的周长,因此是输出0的,

然后考虑偶数的情况,C = 2 * (a + b),那么 a + b = C / 2;由于要输出有多少组,那么直接考虑有多少组不同的整数相加后能够等

于C / 2,因此我们可以看一下测试用例,第一组测试用例C/2 = 3.那么只有一组(1 + 2 = 3),而第二组测试用例C/2  = 10,有

1,9 2,8 3,7 4,6 5,5五组,但是5,5是长和宽相等的情况,因此5,5不符合,而这样的话我们就找到AC这道题的方法了:

解题思路:

1.先看C是奇数还是偶数,奇数输出0,偶数继续判断

2.如果C/2是偶数的话,则要去掉长和宽相等的那一组,因此结果就是C/2/2 - 1.而如果C/2是奇数的话,则结果就是C/2/2.

完整代码实现:

#include
typedef long long LL;
int main(){
    LL n;
    while(scanf("%I64d",&n)==1&&n){
        if(n&1){
            printf("0\n");
        }
        else{
            printf("%I64d\n",(n/2) & 1 ? n/2/2 : n/2/2-1);
        }
    }
    return 0;
}

C题:

C题题目链接

题目描述:

Matrix

TimeLimit:3000MS  MemoryLimit:65536K
64-bit integer IO format: %lld

Problem Description
Given an N*N matrix A, whose elements are either 0 or 1. A[i, j] means the number in the i-th row and j-th column. Initially we have A[i, j] = 0 (1 <= i, j <= N). 

We can change the matrix in the following way. Given a rectangle whose upper-left corner is (x1, y1) and lower-right corner is (x2, y2), we change all the elements in the rectangle by using "not" operation (if it is a '0' then change it into '1' otherwise change it into '0'). To maintain the information of the matrix, you are asked to write a program to receive and execute two kinds of instructions. 

1. C x1 y1 x2 y2 (1 <= x1 <= x2 <= n, 1 <= y1 <= y2 <= n) changes the matrix by using the rectangle whose upper-left corner is (x1, y1) and lower-right corner is (x2, y2). 
2. Q x y (1 <= x, y <= n) querys A[x, y]. 
Input
The first line of the input is an integer X (X <= 10) representing the number of test cases. The following X blocks each represents a test case. 

The first line of each block contains two numbers N and T (2 <= N <= 1000, 1 <= T <= 50000) representing the size of the matrix and the number of the instructions. The following T lines each represents an instruction having the format "Q x y" or "C x1 y1 x2 y2", which has been described above. 
Output
For each querying output one line, which has an integer representing A[x, y]. 

There is a blank line between every two continuous test cases. 
SampleInput
1
2 10
C 2 1 2 2
Q 2 2
C 2 1 2 1
Q 1 1
C 1 1 2 1
C 1 2 1 2
C 1 1 2 2
Q 1 1
C 1 1 2 1
Q 2 1
SampleOutput
1
0
0
1

解析:

这道题是二维线段树和二维树状数组的题目,附上别人的解题报告:

poj 2155 Matrix(二维树状数组)

D题:

D题题目链接

题目描述:

Fibonacci

TimeLimit:1000MS  MemoryLimit:65536K
64-bit integer IO format: %lld

Problem Description

In the Fibonacci integer sequence, F0 = 0, F1 = 1, and Fn = Fn − 1 + Fn − 2 for n ≥ 2. For example, the first ten terms of the Fibonacci sequence are:

0, 1, 1, 2, 3, 5, 8, 13, 21, 34, …

An alternative formula for the Fibonacci sequence is

.

Given an integer n, your goal is to compute the last 4 digits of Fn.

Input

The input test file will contain multiple test cases. Each test case consists of a single line containing n (where 0 ≤ n ≤ 1,000,000,000). The end-of-file is denoted by a single line containing the number −1.

Output

For each test case, print the last four digits of Fn. If the last four digits of Fn are all zeros, print ‘0’; otherwise, omit any leading zeros (i.e., print Fn mod 10000).

SampleInput
0
9
999999999
1000000000
-1
SampleOutput
0
34
626
6875
题意:

给定一个斐波那契数列,第0项是0,第1项是1,第2项是1.....第n项....,然后题目要求的是斐波那契数列的第n项对10000取余后的

结果。

解析:

由于n值范围为(0<=n<=10^9),显然暴力遍历O(n)的算法是会超时的,因此我们要寻找更优的方法去解决这道题

我们看题目中给的提示信息是斐波那契数列的另外一种矩阵的表现形式,而要求第n项,那么我们就要将n个这样的初等矩阵相乘,

矩阵的运算是满足结合律的(关于矩阵的概念和基本性质不清楚的可以自行百度),因此,假如我们将这个初等矩阵记为A,那么要

求A^n的话,我们可以将A视为一个普通的整数,那么对于一个整数取幂次方,利用快速幂的有关知识,便可将O(n)的复杂度降至

O(logn),因此,我们可以将求初等矩阵的幂次方的问题转化成整数快速幂的问题。举例说明:

比如A^19  =>  (A^16)*(A^2)*(A^1),显然采取这样的方式计算时因子数将是log(n)级别的(原来的因子数是

n),不仅这样,因子间也是存在某种联系的,比如A^4能通过(A^2)*(A^2)得到,A^8又能通过(A^4)*(A^4)得到,这点也充

分利用了现有的结果作为有利条件。下面举个例子进行说明:

现在要求A^156,而156(10)=10011100(2) 

也就有A^156=>(A^4)*(A^8)*(A^16)*(A^128)  考虑到因子间的联系,我们从二进制10011100中的最右端开始计

算到最左端。

样例来自:矩阵 快速幂

因此有了这样的想法,我们可以将矩阵表示成一个二维数组,然后得出以下核心代码:

while(n){
            if(n & 1){
                _temp = multi(_temp,_matrix);
            }
            _matrix = multi(_matrix,_matrix);
            n = n >> 1;
        }

_matrix = multi(_matrix,_matrix);
这一句代码的作用是,当前考虑到二进制的哪一位,从最低位开始的时候,只是一个初等矩阵,然后开始往高位考虑,当该位为1的

时候,则表示当前考虑到的过渡矩阵是结果矩阵的一个因子(组成部分)。

完整代码实现:

//矩阵快速幂,利用二进制的原理和矩阵乘法结合律的原理
#include
#include
typedef long long LL;
typedef struct node matrix;
struct node{
    LL a[2][2];
};
matrix _matrix;
const LL mod = int(1e4);

void Init(){
    _matrix.a[0][0] = 1;
    _matrix.a[0][1] = 1;
    _matrix.a[1][0] = 1;
    _matrix.a[1][1] = 0;
}

//给定一个矩阵乘以初始矩阵
matrix multi(matrix x,matrix y){
    matrix temp;
    memset(temp.a,0,sizeof(temp));
    temp.a[0][0] = (x.a[0][0] * y.a[0][0] + x.a[0][1] * y.a[1][0]) % mod;
    temp.a[0][1] = (x.a[0][0] * y.a[0][1] + x.a[0][1] * y.a[1][1]) % mod;
    temp.a[1][0] = (x.a[1][0] * y.a[0][0] + x.a[1][1] * y.a[1][0]) % mod;
    temp.a[1][1] = (x.a[1][0] * y.a[0][1] + x.a[1][1] * y.a[1][1]) % mod;
    return temp;
}

void solve(){
    LL n;
    while(scanf("%I64d",&n)==1 && n!=-1){
        if(n==0){
            printf("0\n");
            continue;
        }
        Init();
        matrix _temp = _matrix;          //用来临时存储结果
        LL ans = 1;
        n -= 1;
        while(n){
            if(n & 1){
                _temp = multi(_temp,_matrix);
            }
            _matrix = multi(_matrix,_matrix);
            n = n >> 1;
        }
        printf("%I64d\n",_temp.a[0][1]);
    }
}

int main(){
    solve();
    return 0;
}


推荐两篇讲快速幂和矩阵快速幂的文章:

快速幂运算

矩阵 快速幂

E题:

E题题目链接

题目描述:

Quasi Binary

TimeLimit:2000MS  MemoryLimit:256MB
64-bit integer IO format: %I64d

Problem Description

A number is called quasibinary if its decimal representation contains only digits 0 or 1. For example, numbers 0, 1, 101, 110011 — are quasibinary and numbers 2, 12, 900 are not.

You are given a positive integer n. Represent it as a sum of minimum number of quasibinary numbers.

Input

The first line contains a single integer n (1 ≤ n ≤ 106).

Output

In the first line print a single integer k — the minimum number of numbers in the representation of number n as a sum of quasibinary numbers.

In the second line print k numbers — the elements of the sum. All these numbers should be quasibinary according to the definition above, their sum should equal n. Do not have to print the leading zeroes in the numbers. The order of numbers doesn't matter. If there are multiple possible representations, you are allowed to print any of them.

SampleInput 1
9
SampleOutput 1
9
1 1 1 1 1 1 1 1 1
SampleInput 2
32
SampleOutput 2
3
10 11 11

题意:

给定一个数n(1 <= n <= 10^6),找出该数至少能由几个只含0和1的数字组成,输出个数以及这些数,不考虑这些数的顺序。

解析:

给定的一个数n,考虑每一位,我们发现,如果这一位大于等于1的话,那么这一位取1必然是最优解,而如果这一位小于1的

话,即这一位为0,那么这一位只能取0,而每一位的数最大即为9,因此给定的数最多拆成9个只含0和1的数字,有了这样的思路,

我们就可以从最低位开始考虑,一直到这个数为0为止。

完整代码实现:

#include
#include
int n,t,g[10];
int main(){
    while(scanf("%d",&n) == 1 && n){
        memset(g,0,sizeof(g));
        int sum = 0,s = 1;
        while(n){
           t = n % 10;
           for(int i = 0;i < t;++i){
                g[i] += s;
           }
           if(t > sum) sum = t;
           n /= 10;
           s *= 10;
        }
        printf("%d\n",sum);
        for(int i = 0;i < 10;++i){
            if(g[i]){
                printf("%d ",g[i]);
            }
        }
        printf("\n");
    }
    return 0;
}


F题:

F题题目链接

题目描述:

Game

TimeLimit:2000MS  MemoryLimit:256MB
64-bit integer IO format: %I64d
Problem Description

Two players play a simple game. Each player is provided with a box with balls. First player's box contains exactly n1balls and second player's box contains exactly n2 balls. In one move first player can take from 1 to k1 balls from his box and throw them away. Similarly, the second player can take from 1 to k2 balls from his box in his move. Players alternate turns and the first player starts the game. The one who can't make a move loses. Your task is to determine who wins if both players play optimally.

Input

The first line contains four integers n1, n2, k1, k2. All numbers in the input are from 1 to 50.

This problem doesn't have subproblems. You will get 3 points for the correct submission.

Output

Output "First" if the first player wins and "Second" otherwise.

SampleInput 1
2 2 1 2
SampleOutput 1
Second
SampleInput 2
2 1 1 1
SampleOutput 2
First
 
    
Note

Consider the first sample test. Each player has a box with 2 balls. The first player draws a single ball from his box in one move and the second player can either take 1 or 2 balls from his box in one move. No matter how the first player acts, the second player can always win if he plays wisely.

题意:

给定四个数,分别是n1,n2,k1,k2,然后n1表示玩家1球的个数,n2表示玩家2球的个数,k1表示玩家1每次扔球的上限,而k2

表示玩家2每次扔球的上限(均为扔自己的球),然后依次轮换扔球,直到某个人没有球可扔,则判定该人输。考虑两个玩家都足够

聪明。

解析:

这道题咋一看还以为是博弈的题目,其实就是水题...只要玩家2的球个数比玩家1多,那么玩家2是必胜的(玩家2可以每次只扔一个

球),反之则玩家1胜利(玩家1也每次只扔一个球),因此完整代码实现如下:

#include
int main(){
    int n1,n2,k1,k2;
    while(scanf("%d%d%d%d",&n1,&n2,&k1,&k2)==4){
        if(n1 > n2){
            puts("First");
        }
        else{
            puts("Second");
        }
    }
    return 0;
}




你可能感兴趣的:(fjut,ACM集训队周赛题解)