湖南大學程序設計競賽新生賽(第一部分)

由於篇幅過長,第二部分在本博客中,傳送門

概述:

今天的題很難,我巨水,就ac了6道題,看來還是要努力呀!
湖南大學程序設計競賽新生賽的網址,可自行去提交評測,傳送門
在這裏插入圖片描述

information:

在這裏插入圖片描述


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:
在這裏插入圖片描述
輸入描述:
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 <bits/stdc++.h>
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 <bits/stdc++.h>
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次……最終遍歷次數不會超過mi=1kXi. m*\sum_{i=1}^{k}Xi.其中i=1kXi=n,k=ans \sum_{i=1}^{k}Xi=n,k=ans
#include<bits/stdc++.h>
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 <bits/stdc++.h>
#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。
  • 證明:
    在這裏插入圖片描述
#include<bits/stdc++.h>
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 <bits/stdc++.h>
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 <bits/stdc++.h>
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;
}

由於篇幅過長,第二部分在本博客中,傳送門

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章