SCAU--ACM--team--2019级寒假训练Beginers Problem(一)合集---SCAU--LEO

作为刚进ACM校队的新手,一定量的题目是很有必要的,对于想学算法的同学来说,一定量的题目也是加强算法的好办法。

这里是后面写完补上的!!
终于写完啦哈哈!!
唔,别急,这只是寒假第一周的作业嘞,嗯哼,我们估计要提早一个多星期开学,后面还有更多大的安排,更多的挑战,加油面对哈!!
写完的感觉真的爽,省赛加油!!!

一.A - Hex-a-bonacci

A - Hex-a-bonacci
Given a code (not optimized), and necessary inputs, you have to find the output of the code for the inputs. The code is as follows:
int a, b, c, d, e, f;
int fn( int n ) {
if( n == 0 ) return a;
if( n == 1 ) return b;
if( n == 2 ) return c;
if( n == 3 ) return d;
if( n == 4 ) return e;
if( n == 5 ) return f;
return( fn(n-1) + fn(n-2) + fn(n-3) + fn(n-4) + fn(n-5) + fn(n-6) );
}
int main() {
int n, caseno = 0, cases;
scanf("%d", &cases);
while( cases-- ) {
scanf("%d %d %d %d %d %d %d", &a, &b, &c, &d, &e, &f, &n);
printf(“Case %d: %d\n”, ++caseno, fn(n) % 10000007);
}
return 0;
}
Input
Input starts with an integer T (≤ 100), denoting the number of test cases.

Each case contains seven integers, a, b, c, d, e, f and n. All integers will be non-negative and 0 ≤ n ≤ 10000 and the each of the others will be fit into a 32-bit integer.

Output
For each case, print the output of the given code. The given code may have integer overflow problem in the compiler, so be careful.

Sample Input
5

0 1 2 3 4 5 20

3 2 1 5 0 1 9

4 12 9 4 5 6 15

9 8 7 6 5 4 3

3 4 3 2 54 5 4

Sample Output
Case 1: 216339

Case 2: 79

Case 3: 16636

Case 4: 6

Case 5: 54

我对题目的理解与思路

首先看到这道题目的时候,应该已经知道了,这题就是优化代码,原代码是正确的但是会超时,不难发现,对于一个大于6的数他的值等于前6个数之和,所以这题可以这样写。
1.创建一个数组(稍微比n的值大一点),用来存每个数对应的值。
2.将0–5的数全部存入数组,然后两个循环,第一个循环是从6开始到n,第二个循环是从i-6开始到i,累加和。(注意此处,对于累加的过程和结果都要求余)
3.输出a[n],即得正确结果。

代码如下

#include<stdio.h>
int a, b, c, d, e, f;
int main() {
    int n, caseno = 0, cases;
    scanf("%d", &cases);
    while( cases-- ) {
        scanf("%d %d %d %d %d %d %d", &a, &b, &c, &d, &e, &f, &n);
        long long g[10003]={0};
        g[0]=a;g[1]=b;g[2]=c;g[3]=d;g[4]=e;g[5]=f;
        for(int i=6;i<=n;i++)
        {
            for(int j=i-6;j<i;j++)
            {
                g[i]=(g[i]%10000007+g[j]%10000007)% 10000007;
            }
        }
        printf("Case %d: %d\n", ++caseno, g[n] % 10000007);
    }
    return 0;
}

所以本题的思想就是打一个表,直接输出答案,可能会有更好的算法,如果有更好的算法,欢迎楼下留言~~~

二.J - Division by 3

There is sequence 1, 12, 123, 1234, …, 12345678910, … . Now you are given two integers A and B, you have to find the number of integers from Ath number to Bth (inclusive) number, which are divisible by 3.

For example, let A = 3. B = 5. So, the numbers in the sequence are, 123, 1234, 12345. And 123, 12345 are divisible by 3. So, the result is 2.

Input
Input starts with an integer T (≤ 10000), denoting the number of test cases.

Each case contains two integers A and B (1 ≤ A ≤ B < 231) in a line.

Output
For each case, print the case number and the total numbers in the sequence between Ath and Bth which are divisible by 3.

Sample Input
2

3 5

10 110

Sample Output
Case 1: 2

Case 2: 67

个人理解和解题方法。

对于这题,有两种判断方法,第一种:求各个位数的和,可以发现,每3个数中就会有两个可以被3整除。第二种:找规律,将情况列出几种出来,不难发现,规律和上面一样。所以这题就很简单了,直接套公式。
1.首先,将(a-1)和b分别除3再乘2,可以知道里面最少的可以被3整除的个数。(至于为什么是a-1,是因为要避免边界带来的麻烦)

2.对于b再进行一次判断,判断它被3求余后是否等于2,若为2的话能被3整除的个数就加一。具体原理我举个例子,比如说3,4,5.
5能被3求余得2,5/3*2后得到的是前3项对应的可以被3整除的个数,因为由规律不难发现每次若出现余2则个数加1,所以要加1.

3.将得到的个数相减即是答案。

代码如下

#include<stdio.h>
int main()
{
    int T;
    scanf("%d",&T);
    int i=1;
    while(T--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        a=a-1;
        int numa=0,numb=0;
        numa=a/3*2;
        if(a%3==2)
            numa++;
        numb=b/3*2;
        if(b%3==2)
            numb++;
        printf("Case %d: %d\n",i,numb-numa);
        i++;
    }
    return 0;
}

三.Circle in Square

A circle is placed perfectly into a square. The term perfectly placed means that each side of the square is touched by the circle, but the circle doesn’t have any overlapping part with the square. See the picture below.
在这里插入图片描述
Now you are given the radius of the circle. You have to find the area of the shaded region (blue part). Assume that pi = 2 * acos (0.0) (acos means cos inverse).
Input
Input starts with an integer T (≤ 1000), denoting the number of test cases.

Each case contains a floating point number r (0 < r ≤ 1000) denoting the radius of the circle. And you can assume that r contains at most four digits after the decimal point.

Output
For each case, print the case number and the shaded area rounded to two places after the decimal point.

Sample Input
3

20

30.091

87.0921

Sample Output
Case 1: 343.36

Case 2: 777.26

Case 3: 6511.05

Note
This problem doesn’t have special judge. So, be careful about precision problems. Better to add a small value to your result to avoid precision problems. For example, add 10-9 to your result.

个人理解和方法

这道题目可以说是一道学过C语言的人都会写的题,但是有几个坑点,首先注意题目后面说的精度问题,所以在计算结果后面要加上1e-9.
本题就是一个公式解决:s=2r2r-2acos(0.0)rr+1e-9;
具体为什么是这样,还请重回初中学习数学知识。
代码如下

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
int main()
{
    int T,i=1;
    cin>>T;
    while(T--)
    {
        double r,s;
        cin>>r;
        s=2*r*2*r-2*acos(0.0)*r*r+1e-9;
        printf("Case %d: %.2lf\n",i,s);
        i++;
    }
    return 0;
}

四.Ekka Dokka

Ekka and his friend Dokka decided to buy a cake. They both love cakes and that’s why they want to share the cake after buying it. As the name suggested that Ekka is very fond of odd numbers and Dokka is very fond of even numbers, they want to divide the cake such that Ekka gets a share of N square centimeters and Dokka gets a share of M square centimeters where N is odd and M is even. Both N and M are positive integers.

They want to divide the cake such that N * M = W, where W is the dashing factor set by them. Now you know their dashing factor, you have to find whether they can buy the desired cake or not.

Input
Input starts with an integer T (≤ 10000), denoting the number of test cases.

Each case contains an integer W (2 ≤ W < 263). And W will not be a power of 2.

Output
For each case, print the case number first. After that print “Impossible” if they can’t buy their desired cake. If they can buy such a cake, you have to print N and M. If there are multiple solutions, then print the result where M is as small as possible.

Sample Input
3

10

5

12

Sample Output
Case 1: 5 2

Case 2: Impossible

Case 3: 3 4

个人理解和方法

这题很明显是用暴力,但是要注意以下几点,因为奇数和偶数相乘一定是偶数,所以如果W是奇数就直接输出impossible;还要注意,如果有多个答案的话,就输出偶数为最小的那一组,所以我们暴力的时候,从偶数小的到偶数大的开始找;
方法:
1.首先判断W是否为奇数,若为奇数,输出impossible,建议判断奇偶性用位运算,即M&1(若为奇数则返回true,若为偶数则返回false。)
2.接下来的情况都是偶数的情况,因为2是偶数的一个因子,所以我们直接从2开始找,判断M/2是否为奇数,且M/22是否等于M,若满足以上两个条件则输出答案,若不满足则将偶数数字2,继续找。

要注意的点有,这题必须用longlong,否则会溢出。
代码如下:

#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
#define ll long long
bool flag=true;
int main()
{
    int T,i=1;
    cin>>T;
    while(T--)
    {
         ll M;
         cin>>M;
         if(M&1) printf("Case %d: Impossible\n",i);
         else
         {
             for(ll j=2;j<=M/2;j=j*2)
             {
                 if(((M/j)&1)&&(M/j*j==M))
                 {
                     printf("Case %d: %lld %lld\n",i,M/j,j);
                     flag=false;
                     break;
                 }
             }
             if(flag) {
                    printf("Case %d: 1 %lld\n",i,M);
             flag=true;
             }
         }
        i++;
    }
    return 0;
}

五.S - Hidden Secret!

In this problem you are given two names, you have to find whether one name is hidden into another. The restrictions are:

  1.  You can change some uppercase letters to lower case and vice versa.
    
  2.  You can add/remove spaces freely.
    
  3.  You can permute the letters.
    

And if two names match exactly, then you can say that one name is hidden into another.

Input
Input starts with an integer T (≤ 100), denoting the number of test cases.

Each case starts with two lines. Each line contains a name consists of upper/lower case English letters and spaces. You can assume that the length of any name is between 1 and 100 (inclusive).

Output
For each case, print the case number and “Yes” if one name is hidden into another. Otherwise print “No”.

Sample Input
3

Tom Marvolo Riddle

I am Lord Voldemort

I am not Harry Potter

Hi Pretty Roar to man

Harry and Voldemort

Tom and Jerry and Harry

Sample Output
Case 1: Yes

Case 2: Yes

Case 3: No

个人理解和方法

首先呢,这题打大概意思是能否通过以下三个步骤使得两个字符串相同,
1.删除或增加若干个空格
2.交换字母顺序
3.字母可以从大写变小写或者从小写变大写。

方法:
1.对于第一种操作,我们可以看成,整个字符串没有空格。
2.对于第3个操作我们可以将大写字母全部转换为小写字母,以便处理方便。
3.对于交换顺序后是否相等,我们可以统计字母的个数是否相等。
所以综上,这题可以转换为统计单词个数,个数相等就输出yes否则输出no。

代码如下:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
#include<string>
using namespace std;
#define ll long long
bool flag=true;
int main()
{
    int T,k=1;
    cin>>T;
    getchar();
    while(T--){
    string a,b;
    int c[150]={0},d[150]={0};
    int lena,lenb;
       getline(cin,a);
       getline(cin,b);
       for(int i=0;i<=a.size();i++){
           if(a[i]!=' '&&a[i]!='\0'){
                if(a[i]<97) a[i]+=32;
               c[a[i]]++;
           }
       }
       for(int i=0;i<=b.size();i++){
           if(b[i]!=' '&&b[i]!='\0'){
                if(b[i]<97) b[i]+=32;
               d[b[i]]++;
           }
       }
       for(int i=97;i<=122;i++)
           if(c[i]!=d[i]) flag=false;

       if(flag) printf("Case %d: Yes\n",k);
       else{
           printf("Case %d: No\n",k);
           flag=true;
       }
       k++;
    }
    return 0;
}

六.Calm Down

George B. wants to be more than just a good American. He wants to make his daddy proud and become a hero. You know, like Shakib Khan.

But sneaky as he is, he wants a special revolver that will allow him to shoot more often than just the usual six times. This way he can fool and kill the enemy easily (at least that’s what he thinks, and that’s the best he can think). George has kidnapped . . . uh, I mean . . . “invited” you and will only let you go if you help him with the math. The piece of the revolver that contains the bullets looks like this (examples for 6 and 17 bullets):
在这里插入图片描述
There is a large circle with radius R and n little circles each having radius r, are placed inside on the border of the large circle. George wants his bullets to be as large as possible, so there should be no space between the circles. George will decide how large the whole revolver will be and how many bullets it shall contain. Your job is, given R and n, to compute r. You have decided to help, because you know that an idiot can’t make a revolver even if you help him with the math.

Input
Input starts with an integer T (≤ 125), denoting the number of test cases.

Each case contains a real number R (0 < R < 1000 and contains up to at most two places after the decimal point) and an integer n (2 ≤ n ≤ 100).

Output
For each test case, print the case number and r in a single line. Errors less than 10-6 will be ignored.

Sample Input
4

4.0 6

4.0 17

3.14 100

42 2

Sample Output
Case 1: 1.3333333333

Case 2: 0.6209067545

Case 3: 0.0956260953

Case 4: 21

个人理解与做法

这道题目就是一个普通的数学问题,可以通过作图发现
r=sin(pai/n)*R/(1+sin(pai/n))。
代码如下

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<cstring>
#include<string>
using namespace std;
#define ll long long
#define pai acos(-1.0)
int main()
{
    int T,k=1;
    cin>>T;
    while(T--){

        int n;
        double R,r;
        cin>>R>>n;
        r=sin(pai/n)*R/(1+sin(pai/n));
        printf("Case %d: %.10lf\n",k,r);
        k++;
    }
    return 0;
}

七.Agent J

Agent J is preparing to steal an antique diamond piece from a museum. As it is fully guarded and they are guarding it using high technologies, it’s not easy to steal the piece. There are three circular laser scanners in the museum which are the main headache for Agent J. The scanners are centered in a certain position, and they keep rotating maintaining a certain radius. And they are placed such that their coverage areas touch each other as shown in the picture below:
在这里插入图片描述
Here R1, R2 and R3 are the radii of the coverage areas of the three laser scanners. The diamond is placed in the place blue shaded region as in the picture. Now your task is to find the area of this region for Agent J, as he needs to know where he should land to steal the diamond.
Input
Input starts with an integer T (≤ 1000), denoting the number of test cases.

Each case starts with a line containing three real numbers denoting R1, R2 and R3 (0 < R1, R2, R3 ≤ 100). And no number contains more than two digits after the decimal point.

Output
For each case, print the case number and the area of the place where the diamond piece is located. Error less than 10-6 will be ignored.

Sample Input
3

1.0 1.0 1.0

2 2 2

3 3 3

Sample Output
Case 1: 0.16125448

Case 2: 0.645017923

Case 3: 1.4512903270

简单说下个人思路和做法

这题的意思很明显,就是让你算蓝色部分的面积,做法就是将三个圆的圆心连起来,用三角形的面积减去三个扇形的面积,三角形的面积可以通过海伦公式算出,公式:p=(a+b+c)/2,
S=sqrt(p*(p-a)(p-b)(p-c));
扇形的面积可以通过公式S=1/2*(弧度)rr;
有人也许会问弧度怎么算,下面给出方法,由数学方法可以知道
arcos(cos)算出来的是弧度,那么cos可以通过三角函数算出,因为三边已知。

下面给出代码

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
#define pai acos(-1.0)
int main()
{
    int T,k=1;
    cin>>T;
    while(T--)
    {
        double R1,R2,R3,a,b,c,S,cos1,cos2,cos3;
        cin>>R1>>R2>>R3;
        a=R1+R3;
        b=R1+R2;
        c=R2+R3;
        cos1=(a*a+b*b-c*c)/(2*a*b);
        cos2=(c*c+b*b-a*a)/(2*b*c);
        cos3=(a*a+c*c-b*b)/(2*a*c);
        S=sqrt((a+b+c)/2*(a+b-c)/2*(a+c-b)/2*(b+c-a)/2);//总面积
        S=S-1.0/2*(acos(cos1)*R1*R1+acos(cos2)*R2*R2+acos(cos3)*R3*R3);
        printf("Case %d: %.10lf\n",k,S);
        k++;
    }
    return 0;
}

八.Higher Math

You are building a house. You’d prefer if all the walls have a precise right angle relative to the ground, but you have no device to measure angles. A friend says he has a great idea how you could ensure that all walls are upright: All you need to do is step away a few feet from the wall, measure how far away you are from the wall, measure the height of the wall, and the distance from the upper edge of the wall to where you stand. You friend tells you to do these measurements for all walls, then he’ll tell you how to proceed. Sadly, just as you are done, a timber falls on your friend, and an ambulance brings him to the hospital. This is too bad, because now you have to figure out what to do with your measurements yourself.

Given the three sides of a triangle, determine if the triangle is a right triangle, i.e. if one of the triangle’s angles is 90 degrees.

Input
Input starts with an integer T (≤ 200), denoting the number of test cases.

Each test case consists of three integers 1 ≤ a, b, c ≤ 40000 separated by a space. The three integers are the lengths of the sides of a triangle.

Output
For each case, print the case number and “yes” or “no” depending on whether it’s a right angle or not.

Sample Input
2

36 77 85

40 55 69

Sample Output
Case 1: yes

Case 2: no

个人思路和做法

首先这题前面一堆都是废话,如果想练练英语阅读能力的话可以看看,这题经过简化后,大概的问题就是,问给出3边,这3边能否组成一个直角三角形。
思路:这题因为输入的是整数,所以直接勾股定理就好了。
做法:
1.定义一个大小为3的long long类型的数组(因为考虑到如果是int类型的话,平方后可能会溢出,所以用long long)
2.用sort对数组进行排序(免去了分类讨论)
3.大数的平方等于两个小数的平方和就输出yes,否则输出no

代码如下:

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
using namespace std;
#define ll long long
int main()
{
    int T,k=1;
    cin>>T;
    while(T--)
    {
         ll a[3];
          for(int i=0;i<3;i++)
              cin>>a[i];
          sort(a,a+3);
          if(a[0]*a[0]+a[1]*a[1]==a[2]*a[2]) printf("Case %d: yes\n",k);
          else printf("Case %d: no\n",k);
        k++;
    }
    return 0;
}

九.Array Simulation

I am retired now, so, no work, a lot of time to spare and a lot of problems to share. Well, finally I am thinking of the old days when I was a solver. But now I am stuck with a tough problem that I want to share with you.

Given an array and some operations on the array, you have to print the final state of the array. Say, the array is a[], the size is n and indexed from 0 to n-1.

The operations are:

  1.  'S D'. D is an integer. D will be added with all the elements of the array.
    
  2.  'M D'. D is an integer. All the elements of the array will be multiplied by D.
    
  3.  'D K'. K is a non zero integer. All the elements of the array will be divided by K (integer division).
    
  4.  'R'. It means reverse. It will reverse the elements of the array.
    
  5.  'P Y Z'. Y and Z are integers. It will swap the elements a[Y] and a[Z].
    

Input
Input starts with an integer T (≤ 100), denoting the number of test cases.

Each case contains two integers n (1 ≤ n ≤ 100) and m (0 ≤ m ≤ 101). The next line contains n space separated integers denoting the elements of the array. Each of the next m lines contains an operation defined above. You can assume that no operation will overflow/underflow the 32 bit signed integer range or access any invalid array reference.

Output
For each case, print the case number first. In the next line you have to print the elements of the array. Two elements should be separated by a single space. There should be no trailing space after the last integer of the array.

Sample Input
2

5 3

1 2 3 4 5

P 0 1

S 1

R

4 2

2 7 8 1

M 10

D 5

Sample Output
Case 1:

6 5 4 2 3

Case 2:

4 14 16 2

个人理解和ways

首先这道题题目题意很明确,就是数组的模拟(说白了就是对数组进行操作),这题没什么难点,直接找出操作对应得字符,进行对应得操作即可。

代码如下:

#include<algorithm>
#include<iostream>
#include<cstdio>
#include<cmath>
#include<string>
#include<cctype>
using namespace std;
#define ll long long
bool flag=false;
int main()
{
    int T,k=1;
    cin>>T;
    while(T--)
    {
       printf("Case %d:\n",k);
       int n,m;
       int a[200];
       cin>>n>>m;
       for(int i=0;i<n;i++) cin>>a[i];
       getchar();
       while(m--)
       {
          string b;
          int j=2;
          int op=0;
            getline(cin,b);
            if(b[0]=='P')
            {
                int j=2,op1=0,op2=0;
                for(;j<b.size();j++)
                    {
                      if(isdigit(b[j]))
                        op1=op1*10+b[j]-48;
                        else break;
                    }
                    j++;
                for(;j<b.size();j++)
                    {
                      if(isdigit(b[j]))
                        op2=op2*10+b[j]-48;
                        else break;
                    }
                    swap(a[op1],a[op2]);
                    continue;
            }
          if(b[2]=='-') {
                flag=true;
                    j++;
          }
           for(;j<b.size();j++)
           {
                op=op*10+b[j]-48;
           }
          if(flag)
          {
              op=(-1)*op;
              flag=false;
          }
          if(b[0]=='S')
          {
              for(int i=0;i<n;i++)
                {a[i]+=op;
                }
          }
          else if(b[0]=='M')
          {
              for(int i=0;i<n;i++)
                a[i]*=op;
          }
          else if(b[0]=='D')
          {
            for(int i=0;i<n;i++)
                a[i]/=op;
          }
          else if(b[0]=='R')
          {
              for(int i=0;i<n/2;i++)
              {
                  swap(a[i],a[n-1-i]);
              }
          }
    }
    for(int i=0;i<n;i++)
        {
            if(i<n-1)
            cout<<a[i]<<" ";
            else cout<<a[i]<<endl;
        }
        k++;
    }
    return 0;
}

十.Secret Origins

This is the tale of Zephyr, the greatest time traveler the world will never know. Even those who are aware of Zephyr’s existence know very little about her. For example, no one has any clue as to which time period she is originally from.

But we do know the story of the first time she set out to chart her own path in the time stream. Zephyr had just finished building her time machine which she named - “Dokhina Batash”. She was making the final adjustments for her first trip when she noticed that a vital program was not working correctly. The program was supposed to take a number N, and find what Zephyr called its Onoroy value.

The Onoroy value of an integer N is the number of ones in its binary representation. For example, the number 13 (11012) has an Onoroy value of 3. Needless to say, this was an easy problem for the great mind of Zephyr. She solved it quickly, and was on her way.

You are now given a similar task. Find the first number after N which has the same Onoroy value as N.

Input
Input starts with an integer T (≤ 65), denoting the number of test cases.

Each case begins with an integer N (1 ≤ N ≤ 109).

Output
For each case of input you have to print the case number and the desired result.

Sample Input
5

23

14232

391

7

8

Sample Output
Case 1: 27

Case 2: 14241

Case 3: 395

Case 4: 11

Case 5: 16

简单说一下题目的大意,这题的意思是给出一个数,要求求出比这个数大的数而且二进制中1的个数相同的数(而且是第一个出现的)。

简单说下方法和理解吧

这题其实不是很好做,但是有多种方法,第一种当然是模拟,模拟我就不说了,下面说个简单点的做法,就是位运算。
首先给大家介绍一个lowbit运算,这个lowbit运算大多用于树状数组中。lowbit的公式是 N&(-N),它的作用是求这个数中二进制位中的最低位对应的数值大小。

下面是做法
1.首先要求出这个数N(假设input的是N)的二进制中第一次出现1的连续区间(出现一次也叫连续)。
这个怎么求呢?
这个怎么求呢?首先设y=N&(-N),这样就求出了N对应的二进制位中的最低位所对应的数值。然后设num=y+N,此时N+Y后,连续的1都变为了0,连续区间前面的第一个0变成了1。
然后将N&(~num),即可得到连续的1的区间对应的数,因为之前的连续区间都变化成了0,再变一次和原来的就一样了,而没变的则改变了,所以取完且后,剩下所得的值即为连续区间1所对应的值。
2.用公式得答案。
answer=N&(~num)/y>>1|num
有人会问N&(~num)/y>>1这个是什么意思,其实很简单一个数除以它的二进制位中最低位1所对应得数时,它的最低为1所在的位置变成第一位,然后除2,就是向右移1位,减少一个1.
和num取或的原因是什么呢??
因为num对应的二进制,相对于N来说,如果不算上前面讨论的连续区间,他就多了一个1,而前面之所以要少一个1也是如此。
两个取完或后所得答案即为答案。
可能有人要问了,为什么这样算得到的是正确答案,这个不难发现,对于二进制来说,如果你要保持1的个数相同,比如
00000111110,你要保持5个一,必然找到连续区间然后改成0000101111,也就是将最前面的1移到前面,后面的1全部后移。
大致原理就是这样。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
using namespace std;
int main()
{
    int k=1,T,n;
    cin>>T;
    while(T--)
    {
        cin>>n;
        int x,y;
        x=n&(-n);
        y=x+n;
        n =(n&~y)/x>>1|y;
        printf("Case %d: %d\n",k,n);
        k++;
    }
    return 0;
}

十一.O - Juice in the Glass

Once upon a time, there lived a mad programmer. He loved to solve creative problems other than anything. His wife loved him quite a lot but disliked his curiosity for the problems. One day he came from office, his wife gave him a glass of cold lime juice. She was in a romantic mood and waiting for some romantic stuff. But the programmer asked her curiously, “If I give u radius of the top and bottom part of the glass and the height, can you come up with the volume of the glass?” His wife became a bit disappointed but as she is smart she replied with a smile, “You already have drunk some juice, and the glass is not full. If I give you the height of the juice, can you find the volume of the remaining juice in the glass?” Then the programmer kissed his wife and said, “You are the best problem setter in the world!”
在这里插入图片描述
Now he set the same problem for you. The radius of the upper part r1 and lower part r2 is given. If height of the glass is h and height of the juice is p what is the volume of the juice in the glass?

Input
Input starts with an integer T (≤ 100), denoting the number of test cases.

Each case starts with a line containing four integers r1 r2 h p (1 ≤ r2 < r1 ≤ 100, 1 ≤ p ≤ h ≤ 100).

Output
For each case, print the case number and the volume of the juice in the glass. Errors less than 10-6 will be ignored.

Sample Input
2

5 2 3 2

5 2 3 3

Sample Output
Case 1: 58.643062867

Case 2: 122.52211349

简单说下思路

这题就是一道纯数学题,这题用到了圆台公式V=1/3paih*(r1r1+r2r2+r1*r2),
这题关键点是算出中间juice的液面半径,可以有多种方法算出,相似,三角函数等等,
下面给出代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
using namespace std;
#define pai acos(-1.0)
int main()
{
    int k=1,T,n;
    cin>>T;
    while(T--)
    {
          double v,r1,r2,h,p;
          cin>>r1>>r2>>h>>p;
          v=1.0/3*pai*p*((r2*r2)+(r2+p*tan(atan((r1-r2)/h)))*(r2+p*tan(atan((r1-r2)/h)))+r2*(r2+p*tan(atan((r1-r2)/h))));
        printf("Case %d: %.9lf\n",k,v);
        k++;
    }
    return 0;
}

十二.Minimum Arc Distance

You all probably know how to calculate the distance between two points in two dimensional cartesian plane. But in this problem you have to find the minimum arc distance between two points and they are on a circle centered at another point.

You will be given the co-ordinates of the points A and B and co-ordinate of the center O. You just have to calculate the minimum arc distance between A and B. In the picture, you have to calculate the length of arc ACB. You can assume that A and B will always be on the circle centered at O.
在这里插入图片描述
Input
Input starts with an integer T (≤ 100), denoting the number of test cases.

Each case starts with a line containing six integers Ox, Oy, Ax, Ay, Bx, By where (Ox, Oy) indicates the co-ordinate of O, (Ax, Ay) denote the co-ordinate of A and (Bx, By) denote the co-ordinate of B. All the integers will lie in the range [1, 10000].

Output
For each case, print the case number and the minimum arc distance. Errors less than 10-3 will be ignored.

Sample Input
5

5711 3044 477 2186 3257 7746

3233 31 3336 1489 1775 134

453 4480 1137 6678 2395 5716

8757 2995 4807 8660 2294 5429

4439 4272 1366 8741 6820 9145

Sample Output
Case 1: 6641.81699183

Case 2: 2295.92880

Case 3: 1616.690325

Case 4: 4155.64159340

Case 5: 5732.01250253

ways and understand

首先,这题是一道数学题毫无疑问。它的大致意思是求两点之间最短的弧长。这题的解法就是在三角形中解。利用弧长公式L=角度*R;角度就是在三角形中算出来的,注意这个图像有几个特点,它的两条边相等且等于半径,所以求两点直接的距离,只需要求两个即可,然后利用反三角函数求出角度,即得到答案。

代码如下

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
using namespace std;
#define pai acos(-1.0)
int main()
{
    int k=1,T,n;
    cin>>T;
    while(T--)
    {
          double AX,AY,BX,BY,OX,OY,L1,L2,s;
          cin>>OX>>OY>>AX>>AY>>BX>>BY;
          L1=sqrt((AX-OX)*(AX-OX)+(AY-OY)*(AY-OY));
          L2=sqrt((AX-BX)*(AX-BX)+(AY-BY)*(AY-BY));
          s=L1*acos(1-(L2*L2)/(2*L1*L1));
          printf("Case %d: %.8lf\n",k,s);
        k++;
    }
    return 0;
}

十三.Unlucky Bird

A bird was flying on a train line, singing and passing lazy times. After a while it saw a train coming from its behind, so, it speeded up a bit, but remained calm. After a while it saw another train coming towards it from the front side. The bird remained calm thinking that the train coming towards him would be in another line. But after a while it realized that both the trains were on the same line!

So, the stupid brave bird made a plan to stop the accident. So it flew towards the train which was coming from the front side, and after touching the train the bird turned back immediately, and flew until it could touch another train. And after that it turned back, and continued this procedure. The birds’ intention was to signal the drivers such that they could stop the train.

When the trains were d meter way, the drivers realized the abnormal behavior of the strange bird, and saw the opposite trains, and both drivers braked hard! But alas! They were able to stop the collision, but they managed to stop in front of each other leaving no distance. And the brave bird was dead in the middle of the trains. Thousand lives saved, but none remembered the bird.

For simplicity we denote the train (that was behind the bird) as the left train and the other one as the right train. The left train had velocity v1 m/s (meter per second) and the right train had velocity v2 m/s and they saw each other when they were d meter away. The driver in the left train made a deceleration of a1 m/s2 and the driver in the right train made a deceleration of a2 m/s2. And the trains just avoided collision. That means they just stopped when their distance was 0 meter. The bird had constant velocity of v3 m/s. And assume that the bird can turn immediately and can keep its constant velocity. When the trains were d meter away, the bird was somewhere between the trains. Your task is to find the distance covered by the brave bird (from this moment) in meters before sacrificing its life for thousand lives.

Input
Input starts with an integer T (≤ 100), denoting the number of test cases.

Each case starts with a line containing five positive real numbers: v1 v2 v3 a1 a2 (v1 < v3, v2 < v3). No real number will be greater than 1000. And no number contains more than three digits after the decimal point.

Output
For each case, print the case number, d and the distance covered by the bird. Errors less than 10-6 will be ignored.

Sample Input
1

0.5 1.0 2 0.25 0.5

Sample Output
Case 1: 1.50000000 4.0

感叹一下,然后说下思路

天啊撸,没想到从高中毕业,时隔半年,我又重新用到了物理!!!!!!果然知识学到了就学到了
下面说说思路,这题大大概图像是这样的假设xxxxx代表车,
bird代表鸟
--------------- xxxxx------------------- bird----------------xxxxx
速度-------------v1----------------------v3 -------------------v2
加速度----------a1-----------------------0 ------------------- a2
------------------------=======================--------
总距离----------------------------s (等于号包括的那部分)
按高中物理的公式vtvt-v0v0=2as;
可以得到s=v1v1/(2a1)+v2v2/(2a2);
t=max(t1/a1,v2/a2);
s=v3*t;

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
using namespace std;
#define pai acos(-1.0)
int main()
{
    int k=1,T,n;
    cin>>T;
    while(T--)
    {
      double v1,v2,v3,a1,a2,t,d,s;
      cin>>v1>>v2>>v3>>a1>>a2;
      t=max(v1/a1,v2/a2);
      d=pow(v1,2)/(a1*2)+pow(v2,2)/(2*a2);
      s=v3*t;
      printf("Case %d: %.8lf %.8lf\n",k,d,s);
        k++;
    }
    return 0;
}

十四.Knights in Chessboard

Given an m x n chessboard where you want to place chess knights. You have to find the number of maximum knights that can be placed in the chessboard such that no two knights attack each other.

Those who are not familiar with chess knights, note that a chess knight can attack 8 positions in the board as shown in the picture below.
在这里插入图片描述
Input
Input starts with an integer T (≤ 41000), denoting the number of test cases.

Each case contains two integers m, n (1 ≤ m, n ≤ 200). Here m and n corresponds to the number of rows and the number of columns of the board respectively.

Output
For each case, print the case number and maximum number of knights that can be placed in the board considering the above restrictions.

Sample Input
3

8 8

3 7

4 10

Sample Output
Case 1: 32

Case 2: 11

Case 3: 20

大致说下我自己的思路和方法吧

具题目给出的图可以看出来(通过平移马)马全在褐色或黄色格子上是最多。
所以对于行列都大于3的数来说,它的答案就为褐色和黄色格子中数目最多的那个。对于行列其中一个等于1的情况来说,它的答案就算非1的行或列的数。对于行或列其中一个为2的情况来说,可以发现如下规律。
第一行: O O X X O O X X O O X X [ ] [ ]
第二行: O O X X O O X X O O X X [ ] [ ];
不难发现每两个差必有两个圆,最后两个括号填什么也就不用我说了,规律如此。
所以它的周期为4,每4次有一个循环。
所以如果n(行或列,不为2的数)%4<2,它的答案就是(n/4)*4+(n%4)*2;
若n%4>=2,则答案为(n/4)*4+4;

以上是我的解释,下面是代码
原文链接:(出自我的另一篇文章)https://blog.csdn.net/Leo_zehualuo/article/details/103965342

#include <iostream>
#include<cstdio>
using namespace std;
int main()
{
    int T,Case=1;
    cin>>T;
    while(T--)
    {
        int m,n,total;
        cin>>m>>n;
        total=m*n;
        if(n==1||m==1) printf("Case %d: %d\n",Case,total);
       else if(total&1) printf("Case %d: %d\n",Case,total/2+1);
       else if(n== 2||m== 2)
        {
            if(n==2) swap(m,n);
            if(m==2)
            {
                if(n%4<2) printf("Case %d: %d\n",Case,(n/4)*4+(n%4)*2);
                else printf("Case %d: %d\n",Case,(n/4)*4+4);
            }
        }
    else printf("Case %d: %d\n",Case,total/2);
        Case++;
    }
    return 0;
}

十五.Bishops

There is an Infinite chessboard. Two bishops are there. (Bishop means the chess piece that moves diagonally).

Now you are given the position of the two bishops. You have to find the minimum chess moves to take one to another. With a chess move, a bishop can be moved to a long distance (along the diagonal lines) with just one move.

Input
Input starts with an integer T (≤ 10000), denoting the number of test cases.

Each case contains four integers r1 c1 r2 c2 denoting the positions of the bishops. Each of the integers will be positive and not greater than 109. You can also assume that the positions will be distinct.

Output
For each case, print the case number and the minimum moves required to take one bishop to the other. Print ‘impossible’ if it’s not possible.

Sample Input
3

1 1 10 10

1 1 10 11

1 1 5 3

Sample Output
Case 1: 1

Case 2: impossible

Case 3: 2

简单说下我对这题的理解和方法思路

这题的大概意思是有两个国际棋盘中的象(只能走对角线),给出这两个象的坐标,问你它们能否相遇,若能最少走多少步相遇。
这题我没有很好的算法,但是有以下的方法。
在这里插入图片描述
图画的有点丑,希望不要介意,黑色的原点代表坐标都是奇数,×代表坐标都是偶数,⭕代表坐标既有奇数又有偶数。
我们先分两大类讨论。
第一类:两个点在同一条直线上,直接输出1;
第二类:两点不在同一直线上
对于第二类,有以下几种需要讨论的情况,就不一一举例,看代码便可。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
using namespace std;
#define ll long long
int main()
{
    int k=1,T,n;
    cin>>T;
    while(T--)
    {
        int r1,c1,r2,c2;
        cin>>r1>>c1>>r2>>c2;
         if(abs(c1-c2)==abs(r1-r2))
            printf("Case %d: 1\n",k);
         else
         {
             if(!(c1&1)&&!(c2&1))
             {
                 if(!(r1&1)&&!(r2&1)||(r1&1)&&(r2&1))
                    printf("Case %d: 2\n",k);
                 else printf("Case %d: impossible\n",k);
             }
             else if((c1&1)&&(c2&1))
             {
                 if((r1&1)&&(r2&1)||!(r1&1)&&!(r2&1))
                    printf("Case %d: 2\n",k);
                 else printf("Case %d: impossible\n",k);
             }
             else if((c1&1)&&!(c2&1))
             {
                 if((r1&1)&&!(r2&1)||!(r1&1)&&(r2&1))
                    printf("Case %d: 2\n",k);
                 else printf("Case %d: impossible\n",k);
             }
             else if(!(c1&1)&&(c2&1))
             {
                 if(!(r1&1)&&(r2&1)||(r1&1)&&!(r2&1))
                    printf("Case %d: 2\n",k);
                 else printf("Case %d: impossible\n",k);
             }
         }
         k++;
    }
    return 0;
}

十六.Intersection of Cubes

You are given n cubes, each cube is described by two points in 3D space: (x1, y1, z1) being one corner of the cube and (x2, y2, z2) being the opposite corner. Assume that the sides of each of the cubes are parallel to the axis. Your task is to find the volume of their intersection.

Input
Input starts with an integer T (≤ 100), denoting the number of test cases.

Each case starts with a line containing an integer n (1 ≤ n ≤ 100). Each of the next n lines contains six integers x1 y1 z1 x2 y2 z2 (1 ≤ x1, y1, z1, x2, y2, z2 ≤ 1000, x1 < x2, y1 < y2, z1 < z2) where (x1, y1, z1) is the co-ordinate of one corner and (x2, y2, z2) is the co-ordinate of the opposite corner.

Output
For each case, print the case number and volume of their intersection.

Sample Input
2

2

1 1 1 3 3 3

1 1 1 2 2 2

3

7 8 9 20 20 30

2 2 2 50 50 50

13 14 15 18 30 40

Sample Output
Case 1: 1

Case 2: 450

记录一下方法

这题的题目大概意思是叫你求相交cube的体积。
这题怎么求呢?题目给了一个提示给你,
1 ≤ x1, y1, z1, x2, y2, z2 ≤ 1000, x1 < x2, y1 < y2, z1 < z2
这说明了什么???说明了2点在cube的对角线的上端,1在下端。
因为一个相交cube的体积只能减小,不可能增大,所以对于1点来说,我们只要找到相交中的x,y,z中最大,2的话找到最小,就可以得知相交cube的体积了。

代码如下

#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<queue>
using namespace std;
#define ll long long
int main()
{
    int T,k=1;
    cin>>T;
    while(T--)
    {
        int n;
        cin>>n;
        int up[3],down[3];
        int minup[3],maxdown[3],V;
        for(int i=0;i<3;i++) cin>>maxdown[i];
        for(int i=0;i<3;i++) cin>>minup[i];
        for(int i=0;i<n-1;i++)//找到相交立方体的对角线坐标
        {
            for(int j=0;j<3;j++) cin>>down[j];
            for(int j=0;j<3;j++) cin>>up[j];
            for(int j=0;j<3;j++)
            {
               minup[j]=min(up[j],minup[j]);
               maxdown[j]=max(maxdown[j],down[j]);
            }
        }
        if((minup[0]-maxdown[0])<0||(minup[1]-maxdown[1])<0||(minup[2]-maxdown[2])<0){
            printf("Case %d: 0\n",k);
            continue;
        }
        V=(minup[0]-maxdown[0])*(minup[1]-maxdown[1])*(minup[2]-maxdown[2]);
        printf("Case %d: %d\n",k,V);
        k++;
    }
    return 0;
}

十七.Positive Negative Sign

Given two integers: n and m and n is divisible by 2m, you have to write down the first n natural numbers in the following form. At first take first m integers and make their sign negative, then take next m integers and make their sign positive, the next m integers should have negative signs and continue this procedure until all the n integers have been assigned a sign. For example, let n be 12 and m be 3. Then we have

-1 -2 -3 +4 +5 +6 -7 -8 -9 +10 +11 +12

If n = 4 and m = 1, then we have

-1 +2 -3 +4

Now your task is to find the summation of the numbers considering their signs.

Input
Input starts with an integer T (≤ 10000), denoting the number of test cases.

Each case starts with a line containing two integers: n and m (2 ≤ n ≤ 109, 1 ≤ m). And you can assume that n is divisible by 2*m.

Output
For each case, print the case number and the summation.

Sample Input
2

12 3

4 1

Sample Output
Case 1: 18

Case 2: 2

简单说下思路和方法。

这个题目的大概意思是有一个数n能被2m整除(同时意味着,正负次数相同),首先进行m次负数的相加,然后再将之前的负数和与现在进行的m次的正数和相加,依次类推,求出最后的值。

这个题目考到了一点数学或者说规律方面的东西,例如说
-1、-2、-3、4、5、6,
不难发现4和-1所得值为3,剩下两个数也为3,同样推广至m时,会有公式num=n/(2m)mm;
这就是最后所得答案
注:n/(2
m)所得的值是进行的正负循环的次数。
这题要注意一个问题,m和num的定义必须要longlong,num会结果大于
int,m在计算num时的计算过程会大于int

#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<cmath>
using namespace std;
#define ll long long
int main()
{
    int k=1,T,n;
    cin>>T;
    while(T--)
    {
      int n;
       ll num,m;
      cin>>n>>m;
      num=n/(2*m)*(m*m);
      printf("Case %d: %lld\n",k,num);
        k++;
    }
    return 0;
}

十八.February 29

It is 2012, and it’s a leap year. So there is a “February 29” in this year, which is called leap day. Interesting thing is the infant who will born in this February 29, will get his/her birthday again in 2016, which is another leap year. So February 29 only exists in leap years. Does leap year comes in every 4 years? Years that are divisible by 4 are leap years, but years that are divisible by 100 are not leap years, unless they are divisible by 400 in which case they are leap years.

In this problem, you will be given two different date. You have to find the number of leap days in between them.

Input
Input starts with an integer T (≤ 550), denoting the number of test cases.

Each of the test cases will have two lines. First line represents the first date and second line represents the second date. Note that, the second date will not represent a date which arrives earlier than the first date. The dates will be in this format - “month day, year”, See sample input for exact format. You are guaranteed that dates will be valid and the year will be in between 2 * 103 to 2 * 109. For your convenience, the month list and the number of days per months are given below. You can assume that all the given dates will be a valid date.

Output
For each case, print the case number and the number of leap days in between two given dates (inclusive).

Sample Input
4

January 12, 2012

March 19, 2012

August 12, 2899

August 12, 2901

August 12, 2000

August 12, 2005

February 29, 2004

February 29, 2012

Sample Output
Case 1: 1

Case 2: 0

Case 3: 1

Case 4: 3

Note
The names of the months are {“January”, “February”, “March”, “April”, “May”, “June”, “July”, “August”, “September”, “October”, “November” and “December”}. And the numbers of days for the months are {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30 and 31} respectively in a non-leap year. In a leap year, number of days for February is 29 days; others are same as shown in previous line.

ways and understanding

简单说下这题它要求的是两个日期之间有多少个闰年。
先介绍一条公式,它利用了容斥原理
num=year/400+year/4-year/100;
这条公式是用来计算闰年的个数的;
这题为了简化查找的过程,对于输入可以直接对应类型输入,不必到时候一个个找出时间月份。
这题主要分两种情况讨论,第一种是第一次输入的月份是大于等于3月的,这种情况下,对应的年份要++;
第二种情况是第二次输入的月份是小于2月且若等于二月小于29日的情况,这种情况下对应的年份要–;
最后的总数等于num2-(num1-1);
代码如下

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<string>
#include<string.h>
using namespace std;
#define ll long long
char str[13][10]= {"\0","January","February", "March", "April","May",
 "June", "July", "August","September", "October", "November", "December"};
int total(int year)
{
     return year/400+year/4-year/100;
}
int main()
{
   int T,k=1;
   scanf("%d",&T);
   while(T--)
   {
        int num1,num2,data1,data2,m1,m2,num;
        ll year1,year2;
        char month1[10],month2[10];
        scanf("%s %d, %d",month1,&data1,&year1);
        scanf("%s %d, %d",month2,&data2,&year2);
        for(int i=1;i<=12;i++)
        {
            if(!strcmp(month1,str[i]))
            {
                m1=i;
                break;
            }
        }
        for(int i=1;i<=12;i++)
        {
            if(!strcmp(month2,str[i]))
            {
                m2=i;
                break;
            }
        }
        if(m1>2) year1++;
        if(m2<2||m2==2&&data2<29) year2--;
        num=total(year2)-total(year1-1);
        printf("Case %d: %d\n",k,num);
        k++;
   }
   return 0;
}

十九.Area of a Parallelogram

A parallelogram is a quadrilateral with two pairs of parallel sides. See the picture below:
在这里插入图片描述
Now you are given the co ordinates of A, B and C, you have to find the coordinates of D and the area of the parallelogram. The orientation of ABCD should be same as in the picture.

Input
Input starts with an integer T (≤ 1000), denoting the number of test cases.

Each case starts with a line containing six integers Ax, Ay, Bx, By, Cx, Cy where (Ax, Ay) denotes the coordinate of A, (Bx, By) denotes the coordinate of B and (Cx, Cy) denotes the coordinate of C. Value of any coordinate lies in the range [-1000, 1000]. And you can assume that A, B and C will not be collinear.

Output
For each case, print the case number and three integers where the first two should be the coordinate of D and the third one should be the area of the parallelogram.

Sample Input
3

0 0 10 0 10 10

0 0 10 0 10 -20

-12 -10 21 21 1 40

Sample Output
Case 1: 0 10 100

Case 2: 0 -20 200

Case 3: -32 9 1247

简单说下这题的方法和思路

这题的坐标的求法呢,就是利用和相同,
也就是AX+CX=BX+DX;
AY+CY=BY+DY;
对于面积呢,可以计算一个三角形内的面积然后乘2,对于一个三角形的面积怎么算的??可以用海伦公式,三条边可以通过两点之间的距离公式求出。

代码如下

#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<queue>
using namespace std;
#define ll long long
int main()
{
    int T,k=1;
    cin>>T;
    while(T--)
    {
        double AX,AY,BX,BY,CX,CY,DX,DY,S,a,b,c,d,L1;
        cin>>AX>>AY>>BX>>BY>>CX>>CY;
        DX=AX+CX-BX;
        DY=AY+CY-BY;
        L1=sqrt((AX-CX)*(AX-CX)+(AY-CY)*(AY-CY));
        a=sqrt((DX-CX)*(DX-CX)+(DY-CY)*(DY-CY));
        b=sqrt((BX-CX)*(BX-CX)+(BY-CY)*(BY-CY));
        c=sqrt((AX-BX)*(AX-BX)+(AY-BY)*(AY-BY));
        d=sqrt((AX-DX)*(AX-DX)+(AY-DY)*(AY-DY));
        S=sqrt((a+d+L1)*(a+d-L1)*(a+L1-d)*(L1+d-a)*1.0/16)+sqrt((c+b+L1)*(c+b-L1)*(c+L1-b)*(b+L1-c)*1.0/16);
        printf("Case %d: %.0lf %.0lf %.0lf\n",k,DX,DY,S);
        k++;
    }
    return 0;
}

二十. Large Division

Given two integers, a and b, you should check whether a is divisible by b or not. We know that an integer a is divisible by an integer b if and only if there exists an integer c such that a = b * c.

Input
Input starts with an integer T (≤ 525), denoting the number of test cases.

Each case starts with a line containing two integers a (-10200 ≤ a ≤ 10200) and b (|b| > 0, b fits into a 32 bit signed integer). Numbers will not contain leading zeroes.

Output
For each case, print the case number first. Then print ‘divisible’ if a is divisible by b. Otherwise print ‘not divisible’.

Sample Input
6

101 101

0 67

-101 101

7678123668327637674887634 101

11010000000000000000 256

-202202202202000202202202 -101

Sample Output
Case 1: divisible

Case 2: divisible

Case 3: divisible

Case 4: not divisible

Case 5: divisible

Case 6: divisible

简单说下这题的思路和方法。

这题明摆着是大数求余问题,既然能除,那就肯定余数为0;
所以只要将它们存入数组中,然后一个个计算求余,若最后余数为0,说明可以整除,若不为0说明不能整除。
代码如下

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<string>
#include<string.h>
using namespace std;
#define ll long long
int main()
{
   int T,k=1;
   scanf("%d",&T);
    while(T--)
   {
       ll b,num=0;
        string str;
        cin>>str>>b;
        for(int i=0;i<str.size();i++)
        {
            if(isdigit(str[i]))
            num=(num*10+str[i]-48)%b;
        }
        if(!num)
        {
            printf("Case %d: divisible\n",k);
        }
        else printf("Case %d: not divisible\n",k);
        k++;
   }
   return 0;
}

二十一.Double Ended Queue

A queue is a data structure based on the principle of ‘First In First Out’ (FIFO). There are two ends; one end can be used only to insert an item and the other end to remove an item. A Double Ended Queue is a queue where you can insert an item in both sides as well as you can delete an item from either side. There are mainly four operations available to a double ended queue. They are:

  1.  pushLeft(): inserts an item to the left end of the queue with the exception that the queue is not full.
    
  2.  pushRight(): inserts an item to the right end of the queue with the exception that the queue is not full.
    
  3.  popLeft(): removes an item from the left end of the queue with the exception that the queue is not empty.
    
  4.  popRight(): removes an item from the right end of the queue with the exception that the queue is not empty.
    

在这里插入图片描述
Now you are given a queue and a list of commands, you have to report the behavior of the queue.

Input
Input starts with an integer T (≤ 20), denoting the number of test cases.

Each case starts with a line containing two integers n, m (1 ≤ n ≤ 10, 1 ≤ m ≤ 100), where n denotes the size of the queue and m denotes the number of commands. Each of the next m lines contains a command which is one of:

pushLeft x pushes x (-100 ≤ x ≤ 100) in the left end of the queue

pushRight x pushes x (-100 ≤ x ≤ 100) in the right end of the queue

popLeft pops an item from the left end of the queue

popRight pops an item from the right end of the queue

Output
For each case, print the case number in a line. Then for each operation, show its corresponding output as shown in the sample. Be careful about spelling.

Sample Input
1

3 8

pushLeft 1

pushLeft 2

pushRight -1

pushRight 1

popLeft

popRight

popLeft

popRight

Sample Output
Case 1:

Pushed in left: 1

Pushed in left: 2

Pushed in right: -1

The queue is full

Popped from left: 2

Popped from right: -1

Popped from left: 1

The queue is empty

解决问题之道于想法

这道题目就是一道模拟题,只要把过程模拟出来就好,没什么难点,分四种情况就好。

下面是代码(有更好的写法,我觉得我的代码写烂了)

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<string>
using namespace std;
//flag是用来判断是否进行过push或者pop的
bool flag1=false;
bool flag2=true;
int main()
{
    int T,k=1;
    cin>>T;
    while(T--)//case的数目
    {
        flag1=false;
        flag2=true;
        int dl[13];//队列
        int n,m,cur=0;
        cin>>n>>m;
        getchar();
        printf("Case %d:\n",k);
        while(m--)//指令
        {
            string str;
            getline(cin,str);
            if(str[4]=='L')//pushleft
            {
                if(flag2)//如果第一个指令是push或者上个指令是pop
                {
                    flag2=false;
                    cur++;
                }
                flag1=true;
                int i=0,num=0;
                while(isalpha(str[i]))//字母跳过
                    i++;//空格跳过
                i++;
                if(cur==n+1)
                    cout<<"The queue is full"<<endl;
                else if(isdigit(str[i]))//为正数
                {
                    for(int j=i; j<str.size(); j++)
                        num=num*10+str[j]-48;
                    for(int j=cur; j>0; j--)
                        dl[j+1]=dl[j];
                    dl[1]=num;
                    printf("Pushed in left: %d\n",num);
                    cur++;

                }
                else//为负数
                {
                    i++;
                    for(int j=i; j<str.size(); j++)
                        num=num*10+str[j]-48;
                    for(int j=cur; j>0; j--)
                        dl[j+1]=dl[j];
                    dl[1]=-num;
                    printf("Pushed in left: %d\n",-num);
                    cur++;

                }
            }
            else if(str[4]=='R')//pushRight,由上同理
            {
                if(flag2)
                {
                    flag2=false;
                    cur++;
                }
                flag1=true;
                int i=0,num=0;
                while(isalpha(str[i]))
                    i++;
                i++;
                if(cur==n+1)
                    cout<<"The queue is full"<<endl;
                else if(isdigit(str[i]))
                {
                    for(int j=i; j<str.size(); j++)
                        num=num*10+str[j]-48;
                    dl[cur]=num;
                    printf("Pushed in right: %d\n",num);
                    cur++;
                }
                else
                {
                    i++;
                    for(int j=i; j<str.size(); j++)
                        num=num*10+str[j]-48;
                    dl[cur]=-num;
                    printf("Pushed in right: %d\n",-num);
                    cur++;
                }
            }
            else if(str[4]=='e')//popleft
            {
                flag2=true;
                if(flag1)
                {
                    flag1=false;
                    cur--;
                }
                if(cur==0)
                    cout<<"The queue is empty"<<endl;
                else
                {
                    printf("Popped from left: %d\n",dl[1]);
                    for(int j=1; j<cur; j++)
                        dl[j]=dl[j+1];
                    cur--;
                }
            }
            else if(str[4]=='i')//popright
            {
                flag2=true;
                if(flag1)
                {
                    flag1=false;
                    cur--;
                }
                if(cur==0)
                    cout<<"The queue is empty"<<endl;
                else
                {
                    printf("Popped from right: %d\n",dl[cur]);
                    cur--;
                }
            }
        }
        k++;
    }
    return 0;
}

二十二.Fibsieve`s Fantabulous Birthday

Fibsieve had a fantabulous (yes, it’s an actual word) birthday party this year. He had so many gifts that he was actually thinking of not having a party next year.

Among these gifts there was an N x N glass chessboard that had a light in each of its cells. When the board was turned on a distinct cell would light up every second, and then go dark.

The cells would light up in the sequence shown in the diagram. Each cell is marked with the second in which it would light up.

在这里插入图片描述
(The numbers in the grids stand for the time when the corresponding cell lights up)

In the first second the light at cell (1, 1) would be on. And in the 5th second the cell (3, 1) would be on. Now, Fibsieve is trying to predict which cell will light up at a certain time (given in seconds). Assume that N is large enough.

Input
Input starts with an integer T (≤ 200), denoting the number of test cases.

Each case will contain an integer S (1 ≤ S ≤ 1015) which stands for the time.

Output
For each case you have to print the case number and two numbers (x, y), the column and the row number.

Sample Input
3

8

20

25

Sample Output
Case 1: 2 3

Case 2: 5 4

Case 3: 1 5

讲讲这题吧

还有两题,这次一周的训练就要结束啦,开心!
这题呢就是一个找规律的题目,不难发现,对于x轴方向,若x的数为偶数,那么它对应的(x,1)一定为x的平方。
在y轴方向上,不难发现,若y为奇数,那么它在(1,y)对应的值为y的平方。
对于对角线上的数,也可以求出公式,怎么推到的呢,如下:
不难发现,两个数之间差个2n,n为第二个数的前一列所对应的x或y坐标。
然后归纳得an-an-1=2n-2,然后将这个公式累加
an-an-1=2n-2;
an-1-an-2=2
n-4;
an-2-an-3=2n-6;
此处省略一堆
a2-a1=2
n-2n+2;
然后全部累加得到通项公式:an=n*(n-1)+1;
然后呢这题就变得很简单了,
首先:确定数的范围,sqrt(x);
因为整数类型会省略小数点后面的数,所以倘若它这个数的平方不等于原数,那么它一定大于这个数的平方,小于这个数加一的平方。
所以可以分以下几种情况讨论
假设x=sqrt(n),从第三种开始x++,第三种相当于第一二种的else的情况。
第一种:平方后等于原数且为奇数,那么它等于(x,1)
第二种:平方后等于原数且为偶数,那么它的坐标等于(1,x)
第三种:平方后不等于原数,且这个数小于通项公式所得的数,且这个数为奇数
用通项公式所得的数减去原数,所得到的值,即为纵坐标的差值,设这个数为temp,则该点的坐标为(x,x-temp)
第四种:平方后不等于原数,且这个数大于通项公式所得的数,且这个数为奇数
用通项公式所得的数减去原数,所得到的值,即为横坐标的差值,设这个数为temp,则该点的坐标为(x-temp,x)
第五种:平方后不等于原数,且这个数小于通项公式所得的数,且这个数为偶数
用通项公式所得的数减去原数,所得到的值,即为纵坐标的差值,设这个数为temp,则该点的坐标为(x-temp,x)
第六种:平方后不等于原数,且这个数大于通项公式所得的数,且这个数为偶数
用通项公式所得的数减去原数,所得到的值,即为横坐标的差值,设这个数为temp,则该点的坐标为(x,x-temp)
代码如下:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<string>
#include<cmath>
using namespace std;
#define ll long long
int main()
{
    int T,k=1;
    cin>>T;
    while(T--)
    {
        ll s,x,y,num;
        cin>>s;
        num=sqrt(s);
        if(num*num==s&&(s&1))
        {
            printf("Case %d: 1 %lld\n",k,num);
        }
        else if(num*num==s&&!(s&1))
        {
            printf("Case %d: %lld 1\n",k,num);
        }
        else
        {
            num++;
            if((num*(num-1)+1)>s&&(num&1))
            {
                ll temp;
                temp=(num*(num-1)+1)-s;
                printf("Case %d: %lld %lld\n",k,num,num-temp);
            }
            else if((num*(num-1)+1)>s&&!(num&1))
            {
                ll temp;
                temp=(num*(num-1)+1)-s;
                printf("Case %d: %lld %lld\n",k,num-temp,num);
            }
            else if((num*(num-1)+1)==s)
            {
                printf("Case %d: %lld %lld\n",k,num,num);
            }
            else if((num*(num-1)+1)<s&&(num&1))
            {
                ll temp;
                temp=s-(num*(num-1)+1);
                printf("Case %d: %lld %lld\n",k,num-temp,num);
            }
            else
            {
                ll temp;
                temp=s-(num*(num-1)+1);
                printf("Case %d: %lld %lld\n",k,num,num-temp);
            }
        }
        k++;
    }
    return 0;
}

二十三.Sum of Factorials

Given an integer n, you have to find whether it can be expressed as summation of factorials. For given n, you have to report a solution such that

n = x1! + x2! + … + xn! (xi < xj for all i < j)

Input
Input starts with an integer T (≤ 10000), denoting the number of test cases.

Each case starts with a line containing an integer n (1 ≤ n ≤ 1018).

Output
For each case, print the case number and the solution in summation of factorial form. If there is no solution then print ‘impossible’. There can be multiple solutions, any valid one will do. See the samples for exact formatting.

Sample Input
4

7

7

9

11

Sample Output
Case 1: 1!+3!

Case 2: 0!+3!

Case 3: 1!+2!+3!

Case 4: impossible

Note
Be careful about the output format; you may get wrong answer for wrong output format.

简单说下这题的算法和思路

这道题我刚开始写的时候,没怎么注意时间,以为直接枚举所有可以的情况就好了,所以用了DFS,结果超时。
在这超时的基础上我稍微改进了下,同样是DFS,不过选的起点不一样和条件不一样,速度就快了很多。

这题正着搜,肯定会超时,从大到小搜,会快很多。
这题的剪枝用到了阶乘的一个性质,任意一个数的阶乘,一定大于或等于它前面所有数的阶乘的和。
这里要说明一下,我自己以前知识的盲区,0的阶乘也是1。
这题的剪枝可以有以下几步1.对于某一情况下sum(现在目前累加的总数)+2*num【i】(一个数i的阶乘)一定大于或者等于要求的这个数n,否则impossible。(用到了上面说过的阶乘的性质)
2.对于一个数要不要加上去,一定有条件sum+num[i]<=n
这样就11ms通过了这题

代码如下

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
#define ll long long
bool flag=false;
bool vis[23];
ll num[23];
int jl[23];
ll n,sum=0;
void DFS(int x)
{
    if(sum==n&&x<=21&&!flag)
    {
        flag=true;
        for(int i=x-1; i>=0; i--)
        {
            if(i>0)
                printf("%d!+",jl[i]);
                else printf("%d!\n",jl[i]);
        }
    }
    else if(sum<n&&x<=21&&!flag)
    {
        for(int i=20;i>=0;i--)
        {
            if(!vis[i]&&(sum+num[i]<=n)&&(sum+2*num[i])>=n)
            {
                vis[i]=true;
                jl[x]=i;
                sum=sum+num[i];
                DFS(x+1);
                sum=sum-num[i];
                vis[i]=false;
            }
        }
    }
}
int main()
{
    int T,k=1;
    scanf("%d",&T);
    num[0]=1;
    for(int i=1; i<=20; i++)
    {
        num[i]=num[i-1]*i;
    }
    while(T--)
    {
        scanf("%lld",&n);
        printf("Case %d: ",k);
        DFS(0);
        if(!flag)
            printf("impossible\n");
        flag=false;
        k++;
        memset(vis,0,sizeof(vis));
        sum=0;
    }
    return 0;
}

二十四.Digits of Factorial

Factorial of an integer is defined by the following function

f(0) = 1

f(n) = f(n - 1) * n, if(n > 0)

So, factorial of 5 is 120. But in different bases, the factorial may be different. For example, factorial of 5 in base 8 is 170.

In this problem, you have to find the number of digit(s) of the factorial of an integer in a certain base.

Input
Input starts with an integer T (≤ 50000), denoting the number of test cases.

Each case begins with two integers n (0 ≤ n ≤ 106) and base (2 ≤ base ≤ 1000). Both of these integers will be given in decimal.

Output
For each case of input you have to print the case number and the digit(s) of factorial n in the given base.

Sample Input
5

5 10

8 10

22 3

1000000 2

0 100

Sample Output
Case 1: 3

Case 2: 5

Case 3: 45

Case 4: 18488885

Case 5: 1

大致说下

这个二十四题是我见过的最有意思的题目了,灵活的运用了数学公式!!!
首先说明一件事情,假设一个数n的阶乘是sum,进制为k;
那么sum<=k的m次方(通过进制转换的知识就可以推得),
很多人看到这题估计要问,这么大的数怎么存的下??斯特林公式??啥的,
其实并不需要
sum可以分解为sum=1 * 2 * 3 * 4 * … … *m;
此时对两边同时取对数可以得到。
log(sum)=log(1)+log(2)+…+log(m);
所以上述sum<=k的m次方,可以转换为
m=log(sum)/log(k);
对于log(sum),可以用上面的公式打表所得。
此题到此就结束了。
代码如下:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
using namespace std;
#define ll long long
double sum[1000008]={0};
int main()
{
    int T,cas=1;
    scanf("%d",&T);
    sum[1]=0;
    for(int i=2;i<=1000000;i++)
        sum[i]=sum[i-1]+log((double)i);
    while(T--)
    {
        int n,k;
        cin>>n>>k;
        if(n==0) printf("Case %d: 1\n",cas);
        else
        {
            double temp;
            temp=sum[n]/log(k*1.0);
            if(temp!=(double)((int)temp)) temp++;
            cout<<temp<<endl;
            printf("Case %d: %.0lf\n",cas,temp);
        }
        cas++;
    }
    return 0;
}
发布了43 篇原创文章 · 获赞 26 · 访问量 3064

猜你喜欢

转载自blog.csdn.net/Leo_zehualuo/article/details/103948841