WEEK1

目录

I - Download Manager

J - sort

L - 人见人爱A-B

M - 人见人爱A^B

B - Fractions Again?!

C - Maximum Product

D – Division

E - Number Box

F - 1D Pawn

G - Ants

C - Reversible  (AtCoder)


I - Download Manager

Jiajia downloads a lot, a lot more than you can even imagine. Some say that he starts downloading up to 20,000 files together. If 20,000 files try to share a limited bandwidth then it will be a big hazard and no files will be downloaded properly. That is why, he uses a download manager.

If there are T files to download, the download manger uses the following policy while downloading files:

1. The download manager gives the smaller files higher priority, so it starts downloading the smallest n files at startup. If there is a tie, download manager chooses the one with less bytes remaining (for download). We assume that with at least 50 Mega Bytes/sec of bandwidth, n files can be downloaded simultaneously without any problem.

2. The available bandwidth is equally shared by the all the files that are being downloaded. When a file is completely downloaded its bandwidth is instantaneously given to the next file. If there are no more files left except the files that are being downloaded, this bandwidth is immediately shared equally by all remaining files that are being downloaded.

Given the size and completed percentage of each file, your task is to intelligently simulate the behavior of the download manager to find the total time required to download all the files.

Input

The will be at most 10 test cases. Each case begins with three integers T (1 <= T <= 20000), n (1 <= n <= 2000 and 1 <= n <= T) and B (50 <= B <= 1000). Here B denotes the total bandwidth available to Jiajia (In Megabytes/sec). Please note that the download manager always downloads n files in parallel unless there are less than n files available for download. Each of next T lines contains one non-negative floating-point number S (less than 20,000, containing at most 2 digits after the decimal places) and one integer P (0 <= P <= 100). These two numbers denote a file whose size is S megabyte and which has been downloaded exactly P% already. Also note that although theoretically it is not possible that the size of a file or size of its remaining part is a fraction when expressed in bytes, for simplicity please assume that such thing is possible in this problem. The last test case is followed by T=n=B=0, which should not be processed.

Output

For each case, print the case number and the total time required to download all the files, expressed in hours and rounded to 2 digits after the decimal point. Print a blank line after the output of each test case.

Sample

InputOutput
6 3 90 
100.00 90 
40.40 70 
60.30 70 
40.40 80 
40.40 85 
40.40 88 
1 1 56 
12.34 100 
0 0 0
Case 1: 0.66 
Case 2: 0.00

【分析】

持续读入t(总数),nt,bn,给出t个文件大小和完成度,求完成剩余所有未完成的文件的时间,按照数据组号+结果的格式输出。

#include<iostream>
using namespace std;
int main(){
    int t,n,b,cnt = 0;
    while(~scanf("%d%d%d",&t,&n,&b)){
        if(t==0 && n==0 && b==0)    //000退出
            break;

        cnt++;  //case编号

        double s,p; //将p也设为double,方便后面p/100
        double sum = 0; //所有文件剩余大小和

        for(int i = 0; i < t; i++){
            cin >> s >> p;
            sum += s * ( 1 - p / 100);
        }

        printf("Case %d: %.2lf\n",cnt,sum / b);
    }
    return 0;
}

J - sort

给你n个整数,请按从大到小的顺序输出其中前m大的数。

Input

每组测试数据有两行,第一行有两个数n,m(0<n,m<1000000),第二行包含n个各不相同,且都处于区间[-500000,500000]的整数。

Output

对每组测试数据按从大到小的顺序输出前m大的数。

Sample

InputOutput
 
5 3 
3 -35 92 213 -644 
 
213 92 3

【分析】

  • 读入每组数据,输出前m大的数,尽量用scanf和printf防止时间超限。
  • memset(buffer,int c,int count):将c赋值给buffer数组或指针,count是buffer的长度(!memset只能初始化为0或-1)。
  • 采用Hash方法。
#include<iostream>
#include<cstring>
using namespace std;

int Num[1000010];

int main(){
    int n,m;
    while(~scanf("%d%d",&n,&m)){
        memset(Num,0,sizeof(Num));  //将Num数组都置为0
        int d;
        //每读入一个数d,我们就将Num[d+500000] 加一,
        //通过数组的值记录某个数的数量。
        for(int i = 0; i < n; i++){
            scanf("%d",&d);
            Num[d+500000]++;
        }

        int cnt = 0;
        for(int i = 1000000; i >= 0; i--){
            while(Num[i]){  数组值不为0(即存在该数)
                Num[i]--;   //数组值-1
                cnt++;  //数量+1
                if(cnt != m)    //还没满m个
                    printf("%d ",i-500000);
                else    //最后一个输出后换行
                    printf("%d\n",i-500000);
            }
            //m个已经找完
            if(cnt == m)
                break;
        }
    }
    return 0;
}

L - 人见人爱A-B

参加过上个月月赛的同学一定还记得其中的一个最简单的题目,就是{A}+{B},那个题目求的是两个集合的并集,今天我们这个A-B求的是两个集合的差,就是做集合的减法运算。(当然,大家都知道集合的定义,就是同一个集合中不会有两个相同的元素,这里还是提醒大家一下)

呵呵,很简单吧?

Input

每组输入数据占1行,每行数据的开始是2个整数n(0<=n<=100)和m(0<=m<=100),分别表示集合A和集合B的元素个数,然后紧跟着n+m个元素,前面n个元素属于集合A,其余的属于集合B. 每个元素为不超出int范围的整数,元素之间有一个空格隔开.
如果n=0并且m=0表示输入的结束,不做处理。

Output

针对每组数据输出一行数据,表示A-B的结果,如果结果为空集合,则输出“NULL”,否则从小到大输出结果,为了简化问题,每个元素后面跟一个空格.

Sample

InputOutput
3 3 1 2 3 1 4 7
3 7 2 5 8 2 3 4 5 6 7 8 
0 0 
2 3 
NULL 

【分析】

  • 首先要将集合A和集合B分别存入数组a,b中,并且分别进行排序。
  • 遍历数组b,将集合B中的元素依次与集合A中的元素进行比较,直到发现有相同的元素则退出,若集合B遍历完仍没有找到相同的元素,则说明此时数组a的值即为要求的A-B中的其中一个元素,因此输出该元素。
  • 若数组a和b都遍历完成仍没有找到相同的元素,则说明{A-B}为空,输出NULL。(利用相同元素的数量cnt)。
#include<iostream>
#include<algorithm>
using namespace std;
int main(){
    int m,n;
    while(~scanf("%d%d",&n,&m)) {
        if(!n && !m){
            break;
        }
        int a[100],b[100];
        for(int i=0;i<n;i++){
            cin >> a[i];
        }
        sort(a,a+n);    //对A从小到大排序

        for(int i=0;i<m;i++){
            cin >> b[i];
        }
        sort(b,b+m);    //对B从小到大排序

        int cnt = 0;
        for(int i=0;i<n;i++){
            //将B中的数依次与A比较,有相同退出,不相同继续比较
            int j=0;
            while(j<m){
                if(a[i]==b[j]){
                    break;
                }
                else{
                    j++;
                }
            }
            //A有B没有
            if(j == m){
                cout << a[i] << " ";
                cnt++;    //A-B元素数量
            }
        }
        if(cnt == 0){
            cout << "NULL" << endl;
        }
        else{
            cout << endl;
        }    
    }
    
    return 0;
} 

M - 人见人爱A^B

求A^B的最后三位数表示的整数。
说明:A^B的含义是“A的B次方”

Input

输入数据包含多个测试实例,每个实例占一行,由两个正整数A和B组成(1<=A,B<=10000),如果A=0, B=0,则表示输入数据的结束,不做处理。

Output

对于每个测试实例,请输出A^B的最后三位表示的整数,每个输出占一行。

Sample

InputOutput
2 3 
12 6 
6789 10000 
0 0 
8 
984 
1 

【分析】

a^b就是b个a相乘。

#include<iostream>
using namespace std;
int main(){
    int a,b;
    while(cin >> a >> b){
        if(!a && !b)    
            break;

        int div = 1;    //初值为1
        //a^b即1*b遍a
        for(int j = 0; j < b; j++){
            div = (div*a) % 1000;   //取后三位
        }
        cout << div << endl;
    }
}

B - Fractions Again?!

【题意】

对于输入的值k,给出所有满足1/k=1/x+1/y的结果。

【分析】

  • 遍历x求y,记录所有满足的结果。
  • 推导:1 / k = 1 / x + 1 / y;

                  1 / y = 1 / k - 1 / x;

                  1 / y = (x - k) / (k * x);

                   y = k * x / (x - k);

  • 注意x的取值范围:当y->0时,x取到最小值,因为x为整数,所以x最小为k+1

                                      当1/x=1/y=0.5*1/k时,x取到最大值2*k

#include<iostream>
using namespace std;
int main(){
    int k;
    while(~scanf("%d",&k)){
        int x,y;
        int cnt = 0;    //x,y组数
        int a[10005] = {0},b[10005] = {0};

        for(int x = k+1; x <= 2*k; x++){    //注意x的取值范围
            //1/k=1/x+1/y可推导出y=k*x/(x-k)
            //如果不能整除,说明y不存在,跳过
            if(k * x % (x - k)){
                continue;
            }

            y = k * x / ( x - k);
            
            //x > y
            a[cnt] = y;   //将x的可能值放入a数组
            b[cnt] = x;   //将y的可能值放入a数组

            cnt++;  //组数+1
        }

        cout << cnt << endl;

        for(int i = 0; i < cnt; i++){
            printf("1/%d = 1/%d + 1/%d\n",k,a[i],b[i]);
        }
    }
    return 0;
}

C - Maximum Product

【 题意】

对于每一组给出的数据,求其连续子序列乘积的最大值。

【分析】

  • 暴力枚举所有起点和终点,用x记录累积乘积,比较所有乘积,返回最大值。
  • 注意起点不一定是第一个数。
#include<iostream>
using namespace std;

//求最大连续积
long long getmax(int a[],int n){
    long long max = 0;  
    for(int i = 0; i < n; i++){ //起点
        long long sum = 1;   
        for(int j = i; j < n; j++){  
            sum *= a[j];
            if(sum > max){
                max = sum;
            }
        }
    }
    return max;
}

int main(){
    int n;
    int cnt = 0;
    while(~scanf("%d",&n)){
        cnt++;
        int a[n];
        for(int i = 0; i < n; i++){
            cin >> a[i];
        }
        printf("Case #%d: The maximum product is %lld.\n\n",cnt,getmax(a,n));   //注意要输出两个换行
    }
    return 0;
}

D – Division

【题意】

给出一个数n,输出所有满足格式abcde/fghij=n的式子(包含0-9,且每个数只出现一次)。

【分析】

  • 枚举所有fghij的可能值,最小为01234,最大为6位数,判断n*fghij和fghij能否满足格式。
  • 注意:结尾没有空行

                  y最大取值为100000/n

#include<iostream>
using namespace std;

//判断两个五位数是否包含0-9,且每个数字出现一次
bool judge(int x,int y){
    int cnt[10] = {0};  //每个数出现次数
    //判断两个五位数是否包含0-9
    for(int i = 0; i < 5; i++){
        cnt[x % 10]++;
        cnt[y % 10]++;

        x /= 10;
        y /= 10;
    }
    //判断每个数字是否只出现一次
    for(int i = 0; i < 10; i++){
        if(cnt[i] != 1){
            return 0;
        }
    }
    return 1;
}

int main(){
    int n;
    bool f = false;
    while(~scanf("%d",&n)){
        if(n == 0)
            break;

        //第二组输出前有空行
        if(f)   
            cout << endl;
        else
            f = true;

        int flag = 0;
        for(int y = 1234; y <= 100000/n; y++){  //注意y的取值范围
            if(judge(y * n,y)){
                flag = 1;
                printf("%05d / %05d = %d\n",y*n,y,n);
            }
        }
        if(!flag){
            printf("There are no solutions for %d.\n",n);
        }
    }
    return 0;
}

E - Number Box

Problem Statement

You are given a positive integer N.

We have a grid with N rows and N columns, where the square at the i-th row from the top and j-th column from the left has a digit Ai,j​ written on it.

Assume that the upper and lower edges of this grid are connected, as well as the left and right edges. In other words, all of the following holds.

  • (N,i) is just above (1,i), and (1,i) is just below (N,i). (1≤i≤N).
  • (i,N) is just to the left of (i,1), and (i,1) is just to the right of (i,N). (1≤i≤N).

Takahashi will first choose one of the following eight directions: up, down, left, right, and the four diagonal directions. Then, he will start on a square of his choice and repeat moving one square in the chosen direction N−1 times.

In this process, Takahashi visits N squares. Find the greatest possible value of the integer that is obtained by arranging the digits written on the squares visited by Takahashi from left to right in the order visited by him.

Constraints

  • 1≤N≤10
  • 1≤Ai,j​≤9
  • All values in input are integers.

Input

Input is given from Standard Input in the following format:

N
A1,1​A1,2​…A1,N​
A2,1​A2,2​…A2,N​
⋮
AN,1​AN,2​…AN,N​

Output

Print the answer.

Sample 1

InputcopyOutputcopy
4
1161
1119
7111
1811
9786

If Takahashi starts on the square at the 2-nd row from the top and 4-th column from the left and goes down and to the right, the integer obtained by arranging the digits written on the visited squares will be 9786. It is impossible to make a value greater than 9786, so the answer is 9786.

Sample 2

InputOutput
10
1111111111
1111111111
1111111111
1111111111
1111111111
1111111111
1111111111
1111111111
1111111111
1111111111
1111111111

Note that the answer may not fit into a 32-bit integer.

【题意】

给出矩阵,求其每个方向上的数连接后的最大值。

【分析】

通过枚举所有起点,从起点出发各个方向,连接所访问的值,比较获得最大值。

#include<iostream>
using namespace std;
typedef long long ll;
int main() {
    int N;
    cin >> N;
    int a[10][10] = { 0 };
    for (int i = 0; i < N; i++)
        for (int j = 0; j < N; j++)
            scanf("%1d", &a[i][j]);

    //方向:上,下,左,右,左上,右上,左下,右下
    int dx[8] = {-1,1,0,0,-1,-1,1,1};
    int dy[8] = {0,0,-1,1,-1,1,-1,1};

    ll max = -1;
    for (int i = 0; i < N; i++) {
        for (int j = 0; j < N; j++) {//枚举所有起点
            for (int k = 0; k < 8; k++) {//每一个方向选择
                //确定好方向后,连接N个数即可
                int x = i, y = j;//初始化起始点
                ll ans = 0;//记录本次遍历的最大值
                for (int d = 0; d < N; d++) {//数的长度为N
                    ans = ans * 10 + a[x][y];//连接每一个数
                    x = (x + dx[k] + N) % N;//控制数据位置在范围内,超过边界的话回到0
                    y = (y + dy[k] + N) % N;
                }
                max = max > ans ? max : ans;//确定max
            }
        }
    }
    printf("%lld", max);
    return 0;
}

F - 1D Pawn

Problem Statement

There are N squares, indexed Square 1, Square 2, …, Square N, arranged in a row from left to right.
Also, there are K pieces. The i-th piece from the left is initially placed on Square Ai​.
Now, we will perform Q operations against them. The i-th operation is as follows:

  • If the Li​-th piece from the left is on its rightmost square, do nothing.
  • Otherwise, move the Li​-th piece from the left one square right if there is no piece on the next square on the right; if there is, do nothing.

Print the index of the square on which the i-th piece from the left is after the Q operations have ended, for each i=1,2,…,K.

Constraints

  • 1≤K≤N≤200
  • 1≤A1​<A2​<⋯<AK​≤N
  • 1≤Q≤1000
  • 1≤Li​≤K
  • All values in input are integers.

Input

Input is given from Standard Input in the following format:

N K Q
A1​ A2​ … AK​
L1​ L2​ … LQ​

Output

Print K integers in one line, with spaces in between. The i-th of them should be the index of the square on which the i-th piece from the left is after the Q operations have ended.

Sample 1

InputOutput
5 3 5
1 3 4
3 3 1 1 2
2 4 5

At first, the pieces are on Squares 1, 3, and 4. The operations are performed against them as follows:

  • The 3-rd piece from the left is on Square 4. This is not the rightmost square, and the next square on the right does not contain a piece, so move the 3-rd piece from the left to Square 5. Now, the pieces are on Squares 1, 3, and 5.
  • The 3-rd piece from the left is on Square 5. This is the rightmost square, so do nothing. The pieces are still on Squares 1, 3, and 5.
  • The 1-st piece from the left is on Square 1. This is not the rightmost square, and the next square on the right does not contain a piece, so move the 1-st piece from the left to Square 2. Now, the pieces are on Squares 2, 3, and 5.
  • The 1-st piece from the left is on Square 2. This is not the rightmost square, but the next square on the right (Square 3) contains a piece, so do nothing. The pieces are still on Squares 2, 3, and 5.
  • The 2-nd piece from the left is on Square 3. This is not the rightmost square, and the next square on the right does not contain a piece, so move the 2-nd piece from the left to Square 4; Now, the pieces are still on Squares 2, 4, and 5.

Thus, after the Q operations have ended, the pieces are on Squares 2, 4, and 5, so 2, 4, and 5 should be printed in this order, with spaces in between.

Sample 2

InputOutput
2 2 2
1 2
1 2
1 2

Sample 3

InputOutput
10 6 9
1 3 5 7 8 9
1 2 3 4 5 6 5 6 2
2 5 6 7 9 10

【题意】

给出N个方块,K个小球的初始位置,位于哪个方块上,Q次操作,每次操作移动当前小球到右侧相邻位置,若该位置有小球,则不移动,若当前位置在最右,不移动。

Sample 1中,3:第3个球在4号方块上,要向右移到5号方块上

                      3:此时第3个球已经在5号方块上,不用右移

                      1:第1个球在1号方块上,要右移到2号方块上

                      1:此时第1个球在2号方块上,由于3号方块存放了第2个球,所以不动

                      2:第2个球在3号方块上,要向右移到4号方块上

【分析】

简单理解为若小球能往右移动,就移动位置。利用check标记当前位置是否被占用。

#include<iostream>
using namespace std;
int main() {
    int N, K, Q;
    int check[201] = {0};    //若i被占,则check[i]为1;[0,200],只用[1,200]的部分
    int a[201] = {0};    //a[N]表示N号方块上球的号码
    scanf("%d %d %d", &N, &K, &Q);
    
    for (int i = 0; i < K; i++){ 
        scanf("%d", &a[i + 1]);  
        //方块号:[1,N]
        //初始化check数组,表示a[i+1]号方块上有球
        check[a[i + 1]] = 1;    
    }

    for (int i = 0; i < Q; i++) {   //操作次数
        int d;
        scanf("%d", &d);

        int p = a[d] + 1;    //p为a[d]的右边一个数,a[d]中是从左边开始的d-th个数
        if (!check[p] && a[d] != N) {   //右边的方块上没有球且方块不在最右边
            check[a[d]] = 0;//删除原标记
            a[d] = a[d] + 1;//往右移动
            check[a[d]] = 1;//设置新标记
        }
    }
    
    //输出球在几号方块上,结尾没有空格
    for (int i = 1; i <= K - 1; i++)
        printf("%d ", a[i]);
    printf("%d", a[K]);
    return 0;
}

G - Ants

An army of ants walk on a horizontal pole of length l cm, each with a constant speed of 1 cm/s. When a walking ant reaches an end of the pole, it immediatelly falls off it. When two ants meet they turn back and start walking in opposite directions. We know the original positions of ants on the pole, unfortunately, we do not know the directions in which the ants are walking. Your task is to compute the earliest and the latest possible times needed for all ants to fall off the pole.

Input

The first line of input contains one integer giving the number of cases that follow. The data for each case start with two integer numbers: the length of the pole (in cm) and n, the number of ants residing on the pole. These two numbers are followed by n integers giving the position of each ant on the pole as the distance measured from the left end of the pole, in no particular order. All input integers are not bigger than 1000000 and they are separated by whitespace.

Output

For each case of input, output two numbers separated by a single space. The first number is the earliest possible time when all ants fall off the pole (if the directions of their walks are chosen appropriately) and the second number is the latest possible such time.

Sample

InputOutputt
2
10 3
2 6 7
214 7
11 12 7 13 176 23 191
4 8
38 207

【题意】

一条线长为L,有n只蚂蚁在上面,每只蚂蚁有各自的初始位置,蚂蚁会向一个方向爬行直到走出该线,若两只蚂蚁相遇,则各自掉头,求所有蚂蚁走完该条线的最快时间和最慢时间,每只蚂蚁移动速度为1。

【分析】

  • 最快时间就是蚂蚁的初始位置到边界的距离的最小值。
  • 最慢时间为当前位置到边界的最大值。
#include<iostream>
#include<cstdio>
using namespace std;

//求最短距离
int min(int a[],int n,int len){
    int min = 0;
    for(int i = 0; i < n; i++){
        int left = a[i];    //到起点的距离
        int right = len - a[i]; //到终点的距离

        int x = left < right ? left : right;    //选距离近的长度
        min = x > min ? x : min;
    }
    return min;
}

//求最长距离
int max(int a[],int n,int len){
    int max = 0;
    for(int i = 0; i < n; i++){
        int left = a[i];    //到起点的距离
        int right = len - a[i]; //到终点的距离

        int x = left > right ? left : right;    //选距离近的长度
        max = x > max ? x : max;
    }
    return max;
}

int main(){
    int N;
    scanf("%d",&N);
    for(int i = 0; i < N; i++){
        int len,n;
        scanf("%d%d",&len,&n);

        int a[n];
        for(int i = 0; i < n; i++){
            scanf("%d",&a[i]);
        }
        printf("%d %d\n",min(a,n,len),max(a,n,len));
    }
    return 0;
}

C - Reversible  (AtCoder)

【题意】

给出n个字符串,其中相同的或相反的属于同一种字符串,要求输出字符串的种类数量。

【分析】

  • 利用set集合:递增且不重复
  • set方法:

begin() 返回指向第一个元素的迭代器
clear() 清除所有元素
count() 返回某个值元素的个数
empty() 如果集合为空,返回true(真)
end() 返回指向最后一个元素之后的迭代器,不是最后一个元素
equal_range() 返回集合中与给定值相等的上下限的两个迭代器
erase() 删除集合中的元素
find() 返回一个指向被查找到元素的迭代器
get_allocator() 返回集合的分配器
insert() 在集合中插入元素
lower_bound() 返回指向大于(或等于)某值的第一个元素的迭代器
key_comp() 返回一个用于元素间值比较的函数
max_size() 返回集合能容纳的元素的最大限值
rbegin() 返回指向集合中最后一个元素的反向迭代器
rend() 返回指向集合中第一个元素的反向迭代器
size() 集合中元素的数目
swap() 交换两个集合变量
upper_bound() 返回大于某个值元素的迭代器
value_comp() 返回一个用于比较元素间的值的函数

  • reverse(s.begin(),s.end()):将s字符串从begin到end取反
#include<bits/stdc++.h>
using namespace std;

int main(){
    int n;
    cin >> n;
    
    set<string> T;  //set集合:递增且不重复
    int cnt = 0;    //字符串种数
    for(int i = 0; i < n; i++){
        string s;
        cin >> s;

        //T中还没有s,字符串种数+1
        if(T.count(s) == 0){
            cnt++;
        }

        T.insert(s);    //将s插入到T中
        reverse(s.begin(),s.end()); //将s字符串取反
        T.insert(s);    //将取反后的字符串s插入到T中
    }
    cout << cnt;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值