湖南大学程序设计竞赛新生赛(第一部分)

由于篇幅过长,第二部分在本博客中,传送门

概述:

今天的题很难,我巨水,就ac了6道题,看来还是要努力呀!
湖南大学程序设计竞赛新生赛的网址,可自行去提交评测,传送门。
湖南大学程序设计竞赛新生赛(第一部分)_第1张图片

information:

湖南大学程序设计竞赛新生赛(第一部分)_第2张图片


problem A:XORsum

题目描述
    You are given two positive integers l and r,you shoud answer l⊕(l+1)⊕⋯⊕r,where ⊕ denotes the bitwise XOR operation. In XOR operation we perform the comparison of two bits, being 1 if the two bits are different, and 0 if they are the same. For example:
湖南大学程序设计竞赛新生赛(第一部分)_第3张图片
输入描述:
The input contain two integers l ,r (1 ≤ l ≤ r ≤10^18)
输出描述:
The only output line should contain a single integer
样例一:

输入 输出
1 2 3

说明:1⊕2=3
样例二:

输入 输出
3 6 4

说明:3⊕4⊕5⊕6=4


题目大意:求L到R的异或和
核心思路:

  • 暴力会超时,所以要优化。
  • 我们不难发现若n为奇数,则n⊕(n+1)=1,而1⊕1=0,0⊕n=n,我们利用这个来优化我们的代码。
#include 
using namespace std;
int main()
{
    ios::sync_with_stdio(false);
    long long a1, a2; //L到R
    while (cin >> a1 >> a2)
    {
        long long ans = 0, tmp; //tmp作为记录有多少个n⊕(n+1)=1
        if (a1 % 2 == 0)        //若L为偶数
        {
            if (a2 % 2 == 1) //R为奇数
            {
                tmp = (a2 - a1 + 1) / 2;
                if (tmp % 2 == 0)
                    cout << "0" << endl;
                else
                    cout << "1" << endl;
            }
            else //R为偶数
            {
                tmp = (a2 - a1) / 2;
                if (tmp % 2 == 0)
                    cout << a2 << endl;
                else
                {
                    ans = 1 ^ a2;
                    cout << ans << endl;
                }
            }
        }
        else //L为奇数
        {
            if (a2 % 2 == 1) //R为奇数
            {
                tmp = (a2 - a1) / 2;
                if (tmp % 2 == 0)
                    cout << a1 << endl;
                else
                {
                    ans = a1 ^ 1;
                    cout << ans << endl;
                }
            }
            else //R为偶数
            {
                tmp = (a2 - a1 + 1) / 2 - 1;
                if (tmp % 2 == 0)
                {
                    ans = a1 ^ a2;
                    cout << ans << endl;
                }
                else
                {
                    ans = a1 ^ 1 ^ a2;
                    cout << ans << endl;
                }
            }
        }
    }
    return 0;
}

problem B:Special number

题目描述
    HH likes math very much. Today he found some numbers that are special. These special numbers are defined as “numbers that can be divisible by less than 3 positive integers.” Now HH wants to ask you how many special numbers there are in the interval [L,R].
输入描述:
The first line contains two integers L,R — the numbers of is the interval.
( 0 <= L <= R <=1e5 )
输出描述:
Output the number of special numbers in the interval [L,R].
样例一:

输入 输出
3 6 2

说明:Only 3, 5 in 3, 4, 5, 6 are special numbers
样例二:

输入 输出
8 8 0

说明:8 is not special number


题目大意:定义一种特殊数,该数字满足可以被小于3个数整除,现在询问区间[L,R]内有多少个这样的数字?( 0 <= L <= R <=1e5 )
核心思路:

  • 首先,先分析什么是被小于3个数整除,换句话说也就是被2个数或1个数整除,这样就转化到了在区间[L,R]内有多少个素数(0,与1特判)。
  • 0不能算,因为0/0在数学上不成立,1不算素数,但他算特殊数。
    -由于时间的限制,我们可以用埃式素数筛,时间复杂度0(n)。
    -若不知道埃式素数筛可以访问传送门,里面有你想要的。
#include 
using namespace std;
const int M = 1e5 + 5;
bool visit[M + 5] = {0}; //作为标记用,标记1则代表删除
void E_sieve()
{
    int i, j;
    for (i = 2; i * i <= M; i++)
    {
        if (visit[i] == 0)
            for (j = i * i; j <= M; j += i)
                visit[j] = 1;
    }
}
int main()
{
    ios::sync_with_stdio(false);
    int a1, a2;
    E_sieve();
    visit[0] = 1; //特判
    while (cin >> a1 >> a2)
    {
        int ans = 0;
        for (int i = a1; i <= a2; i++)
            if (visit[i] == 0)
                ans++;
        cout << ans << endl;
    }
    return 0;
}


Problem C:Alice’s Army

题目描述 :
    It is said that there are many spirits in Lotus Land like to hang out in winter. Now the winter is revealing, and many spirits are playing tricks in Lotus Land. Reimu, who should have to deal with it, is lying at home, entrusting this matter to Marisa. Unfortunately, Marisa is suddenly ill, so she entrusts this matter to Alice. Since it’s Marisa’s invitation, Alice will certainly not refuse. Therefore, she is considering how to get rid of these spirits.

    Alice has many puppet soldiers. She divides them into m armies based on their weapons. Each army has the same kind of weapon. There are three kinds of weapons: sword, shield and bow (respectively represented by S, D and B). Each army has two attribute values, which respectively represents the power and durability of the army. After investigation, Alice found that there are n spirits in total,each of which had its own power and weapon. The three kinds of weapons restrict each other (Sword restricts shield, shield restricts bow and bow restricts sword). When a weapon is restricted, the power of this party will be reduced by fifty percent during the battle.

    For convenience, Alice wants to defeat them one by one, that is, if she wants to attack the kth sprite, he must defeat the (k-1)th sprite (k>1). If the power of Alice 's army is ai and the sprite’s power is bi, Alice 's army can win the battle only when ai ≥ bi. Each battle will consume one durability of the army. When the durability drops to 0 or Alice fails a battle, she must return to rectify and remake those soldiers (See the example below). Assume that Alice can only lead exactly one army to fight at a time and after each battle, Alice will repair her puppet soldiers immediately. The problem is, how many times does Alice have to return at least?
输入描述:
    The first line contains two integers n,m(1≤n,m≤1000). The next n lines, each line contains one integer bi and a character (1≤bi≤10^9), respectively represents the power and weapon of each sprite. Then, following m lines, each line contains two integers ai, di and a character (1≤ai≤10^9,1≤di≤n), respectively represents the power, the durability and the weapon of each army.
输出描述:
    If Alice can defeat all the sprites, print the minimum times she needs to return.
    Otherwise print “ManShenChuangYi” in a single line.

样例一:

输入 输出
5 2 4
4 S
7 S
99 S
10 B
1 S
10 4 S
100 1 S

说明:
    In the first case, Alice can lead the first army to defeat two sprites at a time. But she can not defeat the third sprite. So, she needs to go back and lead the second army to defeat the third sprite. However, the second army’s durability turns to 0 so she must go back to remake them. The fourth sprite’s bow restricts the first army’s sword,10*0.5=5.0<10, so she needs to lead the second army to defeat the fourth sprite.
样例二:

输入 输出
2 2 ManShenChuangYi
9 S
260817 D
999 1 B
9 2 D

说明:
In the second case, there is no army which can defeat the second sprite.
样例三:

输入 输出
5 2 3
4 S
17 D
99 B
5 S
1 B
10 3 S
50 1 D

说明:
    In the third case, the first army can defeat the 1st 2nd 4th and 5th sprites. The second army can defeat all the sprites.


题目大意:给出n个怪物的能力和武器,m个军队的能力、耐久度和武器。三种武器有相互克制的机制,被克制的一方能力暂时下降50%。怪物需要按照编号顺序依次击败。每次只能选择一个军队出战,每次交战后军队耐久度下降一点,当战败或者耐久度为0时需要返回休整,休整后军队耐久度恢复。问最少需要返回几次能打败所有怪物。

由于本博主水平有限,此题暂时不能AC,避免影响读者的观看理解效果,本博主将出题人的题解发布至此,抱歉。

核心思路:

  • 贪心+模拟+暴力
  • 贪心策略:每次都派能打败最多怪物的军队。
    证明:若选择一个能击败x只怪物的军队,但是有能击败x+k只怪物的军队。那么在后几次对派出的军队作考虑时,需要考虑区间编号为[x+1,x+k]∪[x+k+1,n]的怪物。如果选择能击败x+k只怪物的军队,只需要考虑编号区间为[x+k+1,n]的怪物。显然选择能击败x+k只怪物的军队更优。
  • 模拟注意:
    ①不管是计算能力值变化或者耐久度变化时都不要直接修改原数组的值,因为都是暂时性变化。
    ②不要做整数除法。题目中给出50%这个数字已经在暗示这一点。
  • 时间复杂度分析:
    假设第一次最多能打败X1只怪物,则遍历m个军队时可以保证每个军队遍历次数不会超过X1,即总遍历次数不会超过mX1次。第二次从编号为X1的怪物开始,同理总遍历次数不会超过mX2次……最终遍历次数不会超过 m ∗ ∑ i = 1 k X i . m*\sum_{i=1}^{k}Xi. mi=1kXi.其中 ∑ i = 1 k X i = n , k = a n s \sum_{i=1}^{k}Xi=n,k=ans i=1kXi=n,k=ans
#include
using namespace std;
const int maxn=1005;
struct army
{
    int power,dua;
    char wea;
}a[maxn];
struct sprite
{
    int power;
    char wea;
}b[maxn];
int n,m;
bool restrict(char l,char r) //if l restricts r
{
    return (l=='S'&&r=='D')||(l=='D'&&r=='B')||(l=='B'&&r=='S');
}
int sovle(int f,int p)
{
    int dua=a[p].dua,val=a[p].power;
    while(f<n&&dua)
    {
        --dua;
        int t=val,en=b[f].power;
        if(restrict(a[p].wea,b[f].wea))  t<<=1;
        else if(restrict(b[f].wea,a[p].wea)) en<<=1;
        if(t>=en) ++f;
        else break;
    }
    return f;
}
int f_next(int f)
{
    int max_=0;
    for(int i=0;i<m;++i) max_=max(max_,sovle(f,i));
    return max_;
}
int main()
{
    const int limit=1e9;
    cin>>n>>m;
    assert(n<=1000&&m<=1000);
    for(int i=0;i<n;++i) 
    {
        cin>>b[i].power>>b[i].wea;
        assert(b[i].power<=limit);
        assert(b[i].wea=='S'||b[i].wea=='D'||b[i].wea=='B');
    }
    for(int i=0;i<m;++i) 
    {
        cin>>a[i].power>>a[i].dua>>a[i].wea;
        assert(a[i].power<=limit&&a[i].dua>0&&a[i].dua<=n);
        assert(a[i].wea=='S'||a[i].wea=='D'||a[i].wea=='B');
    }
    int ans=0,p=0;
    while(p<n)
    {
        int to=f_next(p);
        if(to==p) {puts("ManShenChuangYi");return 0;}
        p=to;
        ++ans;
    }
    printf("%d",ans);
    return 0;
}

Problem D:Fake Nim

题目描述 :
    There are two people named DaDa and TuTu. DaDa and TuTu are very close friends and usually play some interesting games (and maybe a little boring). One day they saw a store with n piles of candy, each with ai candy. They wanted to buy it all, but they were too poor to buy all the candy at once. In fact, only one of them can come to the store every day (DaDa buys on the first day), and DaDa can only buy an even number of candy from a pile at a time, and TuTu can only buy odd candy from a pile at a time. In other words, on the first day DaDa will buy an even number of candy from a pile in the store, and the next day TuTu will buy an odd number of candy from a pile in the store, and then buy candy alternately. (Note: if one day DaDa finds that the number of any pile of candy is less than two, then he will not buy any candy on that day. ).
    Unsurprisingly, they took buying candy as a game and agreed that whoever bought the last candy in the store would be the winner of the game.
    Their conversation was inadvertently heard by you as the boss, so do you know who will win the game? (of course, DaDa and TuTu are the smartest people in the world, and they will make their own best decisions.).
输入描述:
    The first line contains one integer n, represents that there are n piles of candy at the beginning.
    The next nlines, each line contains one integer ai, represents the number of candy in the i-th pile.
    Data guarantee:1≤n≤50000,1≤≤2e18.
输出描述:
Output a string:
If DaDa wins, output “DaDa”, otherwise output “TuTu”.

样例一

输入 输出
1 TuTu
999999999

说明:TuTu can buy all the candy the next day.
样例二

输入 输出
2
2 1 TuTu

说明:DaDa can only buy two candies on the first day, So TuTu can buy the last candy the next day.
备注 2e18 = 2000000000000000000;


题目大意:
1、有n(n<=50000)堆石子,每堆石子数目为(1<=<=2e18)个。
2、现在有两个人(A和B)轮流取石子,每回合A只能从某一堆取偶数个石子(大于
零个), B只能从某一堆取奇数个石子。
3、如果所有堆的石子数目<2(此时A不能取),则每次跳过A的回合。
4、现A先取石子,若规定取走最后一块石子的人获胜,问A和B谁将获胜?
核心思路

  • 考虑只有一堆的情况:
    a. 若数目为偶数,则A可以在第一轮取完,A获胜。
    b. 若数目为奇数,则A取完后必定剩余奇数颗,此时B可以一次取完,B获胜。
  • 考虑n(n>1)堆的情况:
    现在A第一轮不可能全部取走,那么在B的回合,只需要使某一堆为奇数个石子,接下来一直不取这一堆,直到最后一次全部取走(这一堆为奇数个所以不可能被A取完),即可以保证所有石子的最后一个必定被B取走,B获胜。
  • 综上:当石子只有一堆且数目为偶数时A获胜,否则B获胜。
  • 时间复杂度O(1)。
#include 
#define ll long long
using namespace std;
const int maxn = 5e4 + 50;
ll a[maxn];
int main()
{
    int n;
    cin >> n;
    for (int i = 1; i <= n; ++i)
        scanf("%lld", &a[i]);
    if (n == 1 && a[1] % 2 == 0)
    {
        cout << "DaDa" << endl;
    }
    else
        cout << "TuTu" << endl;
}

Problem E:Ambulance

题目描述:
    Xu1024 is a boy who is responsible for fixing the bug of HOJ.
     Because the Hunan university ACM freshman competition is coming, Xu1024 find that HOJ still has a lot of functions not realized. To solve this problem, Xu1024 had to worka996schedule.
    Unfortunately, Xu1024 was carried into the ambulance because of exhaustion. More unfortunate thing happened, There is something wrong with the ambulance’s electrical system. The electrical system of the ambulance is very special. There are N wires in system A and N wires in system B, and the ambulance can restart when any i-th wire in system A is connected to line theAi-th wireinsystemB.TheA1,A2,…An is apremutation of n.
     In order to save the child, you decide to reconnect the electric wire so that every wire in system B will be connected with a unique line in system A. How many ways can the ambulance restart? Due to the answer will be very large, you only need to output the answer mod 1,000,000,007.
输入
     The first line contains one integer N(N ≤100000), the number of the system’s wire(s).
     The next line contains N integers, the i-th number is Ai.It is guaranteed that A1,A2,…An is a permutation of n.
输出
     Output an integer which denotes the answer.
样例一

输入 输出
2
1 2 1

说明:
     There two ways to connect the electric wire.
     One is choose the 1st A wire to connect the 1st B wire and choose the 2nd A wire to connect the 2nd B wire.
     Another is choose the 2nd A wire to connect the 1st B wire and choose the 1st A wire to connect the 2nd B wire.
     Only the first way can restart the ambulance.
样例二

输入 输出
3
2 3 1 4

题目大意:
     连线,两边每边n个点,问有多少种方法使得A中至少存在一个a连接到了B中的第Ai根线。
     因为Ai是个全排列,所以题目可以化简为A中至少存在一个第i条线连接到了B中的第i根线。

由于本博主水平有限,此题暂时不能AC,避免影响读者的观看理解效果,本博主将出题人的题解发布至此,抱歉。

核心思路:

  • 连线方法共有n!种。
  • 考虑一个都没连上的情况有多少种记为D。
  • 那么答案就是n!-D。
  • 证明:
    湖南大学程序设计竞赛新生赛(第一部分)_第4张图片
#include
using namespace std;
const long long ha = 1e9+7;
const int maxn = 1e5+10;
long long d[maxn], f[maxn];

void init(){
    d[0]=d[1]=0;    d[2]=1;
    for (int i=3;i<maxn;++i){
        d[i]=(i-1)*(d[i-1]+d[i-2]);
        d[i]%=ha;
    }
    f[0]=1;
    for (int i=1;i<maxn;++i){
        f[i]=f[i-1]*i;  f[i]%=ha;
    }
    return ;
}

bool vis[maxn];

int main(){
    init();
    int n;
    scanf("%d",&n);
    assert(n>=1&&n<=100000);
    for (int i=1;i<=n;++i){
        vis[i]=false;
    }
    int x;
    for (int i=1;i<=n;++i){
        scanf("%d",&x);
        assert(x>=1&&x<=n);
        vis[x]=true;
    }
    for (int i=1;i<=n;++i){
        assert(vis[i]);
    }
    printf("%lld\n",(f[n]-d[n]+ha)%ha);
    return 0;
}


Problem F:Dice

题目描述:
     The dice game is very common in movies. Briefly, the rule is that you need to bet on your choice, and the probability of winning is one-half. If you win, your money will get doubled, otherwise you will lose your money in this round.
     One day, Tom came up with a brilliant strategy to make sure he wouldn’t lose much money. The steps of the strategy are described as following:

  1. He would play n rounds of the dice game at most.
  2. Start betting with 1 dollar in the first round, and double the bet every round.
  3. If he won the game in a round, he would not take part in all the following games.
    Now Tom wants to know the probability of his winning the money using this strategy after the game.
    输如:
        The first line contains a number t(t<=20) indicating that there are t test cases.
        The next t lines contain a number n(n<=20) each, indicating that the maximum round Tom would play.
    输出:
        Please output the probability that Tom will make money.(Reserved to four decimal places)
    样例一:
输入 输出
2
1 0.5000
2 0.7500

说明:
    In the first test case, n equals to 1. The probability of wining and losing are equal, so the probability of winning at the first time is 0.5000.
    In the second test case, n equals to 2. The probability of wining and losing are equal, so the probability of winning at the first time is 0.5000. When lose the game at the first time, the probability of winning at the second time is 0.5000. Therefore the probability that Tom will make money equal to 0.5000 + 0.5000 * 0.5000 = 0.7500
**备注:**Hint:Please use double instead of float.


题目大意:
    赌大小,输赢概率都是1/2,从1块钱开始赌。每次若赢则离开游戏,否则持续赌博并把赌注翻倍,最多赌n场,输出赢钱的概率。
核心思路:

  • 先将[1,20]的所以概况计算出,然后根据输入进行累加。
#include 
using namespace std;
int main()
{
    ios::sync_with_stdio(false);
    int t;
    double a[25] = {0}, tmp = 1.0;
    for (int i = 1; i <= 20; i++)
    {
        tmp *= 0.5;
        a[i] = a[i - 1] + tmp;
    }
    cin >> t;
    while (t--)
    {
        int x;
        cin >> x;
        cout << fixed << setprecision(4) << a[x] << endl;
    }
    return 0;
}

Problem G:The GCD of Fibonacci Numbers

题目描述:
    The Fibonacci sequence is the sequence of numbers such that every element is equal to the sum of the two previous elements, except for the first two elements f0 and f1 which are respectively zero and one. The first few numbers in the Recaman’s Sequence is 0,1,1,2,3,5,8,… The ith Fibonacci number is denoted fi.
    The largest integer that divides both of two integers is called the greatest common divisor of these integers. The greatest common divisor of a and b is denoted by gcd(a,b).
    Two positive integers m and n are given,you must compute the GCD(fm,fn).
输入:
    The first linecontains one integer T(T ≤ 100),the number of test cases.
For each test case,there are two positive integers m and n in one line. (1 ≤m,n ≤ 2^31 , GCD(m,n) ≤ 45)
输出:
    Foreach the case, your program will outputthe GCD(fm,fn).
样例一:

输入 输出
4
1 2 1
2 3 1
2 4 1
3 6 2

题目大意斐波那契与GCD;
核心思路:

  • 利用斐波那契数列与GCD的性质GCD(F(m)+F(n))=F(GCD(m,n))
#include 
using namespace std;
long long a[50]={0,1,1};
void excel()
{
    for(int i=3;i<=46;i++)
        a[i]=a[i-2]+a[i-1];
}
int main()
{
    ios::sync_with_stdio(false);
    int t;
    excel();
    cin >> t;
    while(t--)
    {
        int m,n;
        cin >> m >> n;
        int tmp=__gcd(m,n);
        cout << a[tmp] << endl;
    }
    return 0;
}

由于篇幅过长,第二部分在本博客中,传送门

你可能感兴趣的:(比赛)