北华大学计算机程序设计算法提高训练营个人赛(无L)

北华大学计算机程序设计算法提高训练营个人赛(无L)

明明是北华大学的训练赛,结果被屠榜了hhh,L防ak题吧这也太难了

A-洛姐打题日记

题目描述

洛姐开开心心地打题,可是她看不懂评测机给的判定结果,你能帮帮她吗。

摘自ACM评分标准:

竞赛进行5个小时,一般有7道或以上试题,由同队的三名选手使用同一台计算机协作完成。当解决了一道试题之后,将其提交给评测机,由评测机判断其是否正确。若提交的程序运行不正确,则该程序将被退回给参赛队,参赛队可以进行修改后再一次提交该问题。程序判定结果有如下7种:
1、Accepted. ——通过!(AC)
2、Wrong Answer.——答案错。(WA)
3、Runtime Error.——程序运行出错,意外终止等。(RE)
4、Time Limit Exceeded. ——超时。程序没在规定时间内出答案。(TLE)
5、Presentation Error. ——格式错。程序没按规定的格式输出答案。(PE)
6、Memory Limit Exceeded. ——超内存。程序没在规定空间内出答案。(MLE)
7、Compile Error. ——编译错。程序编译不过。(CE)

(部分OJ还有不同的判定结果,不过在这里不予考虑)

输入描述:
输入一行,表示判定结果的简写
输出描述:
输出一行,表示判定结果的英文全称                  
输入
AC
输出
Accepted

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 2e5 + 50, MOD = 1e9 + 7;

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    string s;
    cin>>s;
    if(s=="AC")cout<<"Accepted";
    else if(s=="WA")cout<<"Wrong Answer";
    else if(s=="RE")cout<<"Runtime Error";
    else if(s=="TLE")cout<<"Time Limit Exceeded";
    else if(s=="PE")cout<<"Presentation Error";
    else if(s=="MLE")cout<<"Memory Limit Exceeded";
    else cout<<"Compile Error";
    return 0;
}

B-鸡兔同笼

题目描述

鸡兔同笼,但,这是外星牧场!!

已知每只外星鸡有一头 x 只脚,每只外星兔有一头 y 只脚。(x≠y)

外星人为了数学教育,曾出过这样一道题。现将一些外星鸡和外星兔关进同一个笼子中,已知笼子中有 H 个头、F 只脚,求笼子中有多少只外星鸡和多少只外星兔。

输入描述:
输入由多个测试用例组成。第一行包含一个整数 ttt,表示测试案例的数量。测试用例的描述如下。(1≤t≤2∗105)
每个测试样例输入一行四个正整数 x,y,H,Fx,y,H,Fx,y,H,F ,含义见题目描述。(1≤x,y,H,F≤109,x!=y)
输出描述:
对于每个测试样例,输出一行两个正整数(用空格分隔),分别表示外星鸡的数量和外星兔的数量。  
输入
2
2 4 8 24
3 4 12 41
输出
4 4
7 5

问题解析

设有a个鸡,b个兔子。方程就是a+b=H和a*x+b *y=F。解方程即可。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 2e5 + 50, MOD = 1e9 + 7;

void solve()
{
    int x,y,h,f;
    cin>>x>>y>>h>>f;
    int b=(h*x-f)/(x-y);
    int a=h-b;
    cout<<a<<" "<<b<<endl;
}

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int t;
    cin>>t;
    while(t--)
        solve();
    return 0;
}

C-小杜的签到

题目描述

小袁经常苦恼于找不到好题,于是,一旁的小杜献上了一道锦囊妙题。

现有一个长为 n 的数组 a。定义 :
F ( a ) = ∑ i = 1 n − 1 ( a i + 1 − a i ) F(a)=\sum_{i=1}^{n-1}{(a_{i+1}-a_i)} F(a)=i=1n1(ai+1ai)

每次操作可以选择一个 i,满足
1 ≤ i < n 1≤i<n 1i<n
,并交换
a i 和 a i + 1 ai 和 ai+1 aiai+1
任意次数操作后(可能是 0 次),小杜想知道 F(a) 的最小值和最大值分别是多少。

输入描述:
第一行输入一个正整数 n,表示数组 a 的长度。(2≤n≤106)
第二行输入 n 个正整数 ai,表示这个数组。(1≤ai≤109)
输出描述:
输出一行两个正整数,分别表示 F(a)F(a)F(a) 的最小值和最大值。(用空格分隔)                
输入
3
3 2 1
输出
-2 2

问题解析

把数组升序排序后得到的就是最大值,乘上-1(或把数组降序排序后再算一遍)得到的就是最小值。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 2e5 + 50, MOD = 1e9 + 7;

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n;
    cin>>n;
    vector<int>v(n);
    for(int i=0;i<n;i++)cin>>v[i];
    sort(v.begin(),v.end());
    int sum=0;
    for(int i=1;i<n;i++)
    {
        sum+=v[i]-v[i-1];
    }
    cout<<-1*sum<<" "<<sum<<endl;
    return 0;
}

D-我超!原!

题目描述

你在城中,见过枯萎的樱花树么?这种「枯」之美,让我想到春天盛开之景。不过别人似乎并不这么想,不再开花的樱树会被移走…就算一次也好,真想看到它再次开放。

什么?原来你也玩原神。

作为神里凌华的单推人,小袁在神里凌华上线的第一天就将她拿下了。小袁想快速培养她。

小袁想要将神里凌华升到 x 级,角色的初始等级为 1 级,第一次升级需要 1000 经验,之后每升一级需要花费比上一次升级多 y 点的经验值。小袁不想浪费经验材料。

原神中有三种可以加经验的材料:

  1. ​ 大英雄的经验:20000点;
  2. ​ 冒险者的经验:5000 点;
  3. ​ 流浪者的经验:1000 点。

已知小袁三种材料拥有的数量分别是:A,B,C,求小袁将神里凌华升至 x 级后,溢出的经验最少是多少;或者告诉小袁,他拥有的材料不足以将其升至 x 级。

输入描述:

第一行输入两个正整数 x,y 的含义如题目描述所述。(1≤x,y≤106)
第二行输入三个整数 A,B,C,表示小袁三种材料拥有的数量。(0≤A,B,C≤109)

输出描述:

如果小袁能将神里凌华升至 x 级,输出一行一个非负整数,表示溢出的经验的最小值。
否则输出一个字符串"QAQ"(不含引号),委婉地告诉小袁他不能将神里凌华升至 x 级。                      
输入
5 750
1 2 5
输出
500
说明
升至5级需花费8500经验,使用1“冒险者的经验”和4“流浪者的经验”后,溢出500经验。

问题解析

一开始还想着完全背包,一看复杂度就肯定不是。

直接贪心模拟,先等差数列前n项和算出需要多少经验才能升到x级,但是要注意初始是1级,所以我们算的是前x-1项和。再算一下我们全部资源有多少经验,如果全部资源都用上经验也不够就输出QAQ。

直接贪心,能用20000的就用,用完了或用了会超就用5000,再是1000,最后离升满级就差不到1000经验,我们再看1000的有没有,没有用5000,再没有用20000。

但是有一点,比如所需经验是17000,5000的有4个,1000的有1个,如果我们用了三个5000后用一个1000的,这样还剩1000经验才到目标,此时1000的用完了,我们只能用5000的,超出经验4000,但我们要是一开始就用4个5000的,那超出经验3000。所以我们在算的过程中可以多加一个步骤,我们不继续细分而是直接用当前档次升满级看需要多少经验。最后这两种途径的取最小值即可。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 2e5 + 50, MOD = 1e9 + 7;

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    ll n, m, a, b, c;
    cin >> n >> m >> a >> b >> c;
    ll res = 1000 * (n-1) + ((n-2) * (n - 1)) / 2 * m;
    ll ans = a * 20000 + b * 5000 + c * 1000;
    if (res > ans)
    {
        cout << "QAQ" << endl;
        return 0;
    }
    ans=1e18;
    if (a * 20000 >= res)
    {
        a -= res / 20000;
        res %= 20000;
        if(a>0)ans=min(ans,20000-res);
    }
    else
    {
        res -= a * 20000;
        a = 0;
    }

    if (b * 5000 >= res)
    {
        b -= res / 5000;
        res %= 5000;
        if(b>0)ans=min(ans,5000-res);
    }
    else
    {
        res -= b * 5000;
        b = 0;
    }

    if (c * 1000 >= res)
    {
        c -= res / 1000;
        res %= 1000;
        if(c>0)ans=min(ans,1000-res);
    }
    else
    {
        res -= c * 1000;
        c = 0;
    }
    if (res == 0)cout << res << endl;
    else if (c != 0)cout << min(ans,1000 - res) << endl;
    else if (b != 0)cout << min(ans,5000 - res) << endl;
    else if (a != 0)cout << min(ans,20000 - res) << endl;
    return 0;
}

E-佳乐的迷宫

题目描述

佳乐特别喜欢玩走迷宫,是当今世界的迷宫大师。现在,有一座特殊的二维矩阵迷宫横空出世,佳乐想前去挑战一下。已知有 k 个入口和 1 个出口,请你帮佳乐看看,从哪几个入口进入能够走到出口。

输入描述:
第一行输入三个正整数 n,m,k  ,分别表示二维矩阵迷宫的长宽,入口的数量。(1≤n,m≤1000)
接下来 n 行每行输入 m 个字符, '.' 表示为道路,'#' 表示为墙壁。
接下来 k 行每行输入两个正整数 xi,yi,表示入口的位置。保证入口所在的地方为 '.' 。
接下来 1 行输入两个正整数X,Y,表示出口的位置。保证出口所在的地方为 '.' 。保证所有出口入口互不相同。(1≤xi,X≤n,1≤yi,Y≤m)
输出描述:
第一行输出一个整数 p,表示有几个入口进入能走到出口。
第二行输出 p 个整数,第 i 个数 si ,表示从第 si 个入口进入可以走到出口。(si 按顺序输出,之间用空格隔开)                
输入
3 3 2
.##
#..
..#
1 1
3 1
2 3
输出
1
2

问题解析

可以先把入口的位置都记录下来,然后我们以出口位置进行bfs(dfs),看那些位置是出口能走到的,那么对应的,这个位置就是能走到出口的,我们再去判断之前那些出口位置有哪些是出口能走到的即可。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 2e5 + 50, MOD = 1e9 + 7;

int st[1050][1050];
int dx[] = { 1,0,-1,0 }, dy[] = { 0,1,0,-1 };
signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n, m, k;
    cin >> n >> m >> k;
    vector<string>v(n);
    for (int i = 0; i < n; i++)cin >> v[i];
    vector<PII>ans(k);
    for (int i = 0; i < k; i++)cin >> ans[i].first >> ans[i].second;
    int x, y;
    cin >> x >> y;
    queue<PII>que;
    que.push({ x,y });
    st[x][y] = 1;
    while (!que.empty())
    {
        int len = que.size();
        for (int i = 0; i < len; i++)
        {
            auto t = que.front();
            que.pop();
            for (int j = 0; j < 4; j++)
            {
                int a = t.first + dx[j], b = t.second + dy[j];
                if (a  >= 1 && b  >= 1 && a  <= n && b  <= m &&v[a-1][b-1] == '.' && st[a ][b] == 0)
                {
                    st[a ][b] = 1;
                    que.push({ a,b });
                }
            }
        }
    }
    vector<int>res;
    int cnt = 0;
    for (auto i : ans)
    {
        cnt++;
        if (st[i.first][i.second])
        {
            res.push_back(cnt);
        }
    }
    cout << res.size() << endl;
    for (auto i : res)cout << i << " ";
    return 0;
}

F-三四五

题目描述

杰哥和洛姐在玩游戏,他们在玩经典的石子游戏。

现在有三堆石子,分别有 n0,n1,n2 个石子。

杰哥和洛姐轮流进行游戏,每次游戏将同时从三堆石子中分别拿走 x0,x1,x2 个石子,满足 x0∈[1,3],x1∈[1,4],x2∈[1,5],保证石堆中石子数量时刻为非负整数。

当一个人在任意一堆中无法拿走石子(即石堆中,有至少一堆的余量为0),他将输掉游戏。

洛姐先手杰哥后手。洛姐想知道,她能否战胜博弈天才杰哥。(双方都使用最优策略进行游戏)

输入描述:
多组输入,第一行输入 t,表示样例数量。(1≤t≤106)
接下去 t 行每行输入三个正整数 n0,n1,n2,表示三堆石子的初始数量。(0≤n0,n1,n2≤109)
输出描述:
如果洛姐获胜,则输出一行字符串 "(^-^)" (不包含引号)。
否则输出一行字符串 "(T-T)" (不包含引号)。                     
输入
2
3 4 5
0 0 0
输出
(^-^)
(T-T)

问题解析

升级办nim游戏,这里先说一个nim游戏的必胜秘诀,如果你每次能拿最多x个石头,那么只要总石头数不是(x+1)的倍数,你就可以赢,如果是则必输。

所以只要第一堆石头是4的倍数or第二堆是5的倍数or第三堆是6的倍数,那么这堆石头我们肯定会输。但这题不是单纯的看是否必输or必赢,而是看谁先输,比如石头数是1,100,20,虽然第二堆石头是5的倍数,我们必输,但是第一堆石头只有1个,我们拿完后对面就直接输了,第一堆石头可以在第一轮分出胜负,而第二堆要20轮才能分出胜负,显然是我们赢。所以我们要看,输最快会在第几轮输,赢最快会在第几轮赢,谁小,那就说明我们会赢(输)。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 2e5 + 50, MOD = 1e9 + 7;

void solve()
{
    int a,b,c;
    cin>>a>>b>>c;
    bool flag=true;
    int winer=1e9,loser=1e9;
    if(a%4==0)loser=min(loser,a/4);
    else winer=min(winer,a/4);
    
    if(b%5==0)loser=min(loser,b/5);
    else winer=min(winer,b/5);
    
    if(c%6==0)loser=min(loser,c/6);
    else winer=min(winer,c/6);
    
    if(winer<loser)cout<<"(^-^)"<<endl;
    else cout<<"(T-T)"<<endl;
}

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int t;
    cin>>t;
    while(t--)
        solve();
    return 0;
}

G-杰哥的疑问

题目描述

有一个巨大的数组,这个数组充满了神秘感。

杰哥给出了一个数 m。杰哥想知道,这个数组中有多少对数的和等于给定的数,即,有多少对 (i,j) 满足 ai+aj=m 且 1≤i<j≤n。

快帮帮杰哥!

输入描述:
第一行输入两个正整数 n,m,分别表示数组的元素个数,以及杰哥给定的数。(1≤n≤106,0≤m≤109)
第二行输入 n 个正整数,第 i 个正整数为 ai。(0≤ai≤109)
输出描述:
输出一行一个正整数,表示满足条件的对的数量。                  
输入
5 5
1 1 2 3 4
输出
3

问题解析

可以用哈希表记录一下每个数的出现次数,然后对于一个数x来说,能和他相加后等于m的数肯定是m-x。那我们只要看m-x这个数出现了多少次,且x又出现了多少次,就可以知道x和m-x一共可以组合出多少个满足条件的数对。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 2e5 + 50, MOD = 1e9 + 7;

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n,m,x,cnt=0;
    cin>>n>>m;
    unordered_map<int,int>mymap;
    for(int i=0;i<n;i++)
    {
        cin>>x;
        cnt+=mymap[m-x];
        mymap[x]++;
    }
    cout<<cnt;
    return 0;
}

H-墨染的斯汀木

题目描述

一天,佳乐拿来了一块神奇的斯汀木作为礼物送给洛姐,这块木头上印有一串神秘的字符。字符仅包含大写或小写的拉丁字母。

洛姐对其上的字符串着了迷,于是,她通过某种操作,将这一串字符转译成了属于自己的字符串,并记录了下来。

已知洛姐转译中可以进行多次(可能是 0 次)以下的操作:

  1. ​ 将相邻两个小写字符合并成一个对应的大写字符,如 “aa” -> “A”;
  2. ​ 将一个大写字符拆分成两个对应的相邻的小写字符,如 “B” -> “bb”;

春去秋来。一天,洛姐发现斯汀木不知什么时候被墨水浸透了,其上的部分字符已经看不清了。意外的是,所有字符均还能区分出大小写。

于是,洛姐拿出了转译的字符串,试图还原斯汀木上的原字符串。

输入描述:
第一行输入一行一个字符串 s0,表示斯汀木上的原字符串。该字符串包含大写或小写的拉丁字母,以及 '!' 和 '?' 。'!' 代表一个看不清的大写拉丁字母,'?' 代表一个看不清的小写拉丁字母。
第二行输入一行一个字符串 s1,表示洛姐转译后的字符串。该字符串仅包含大写或小写的拉丁字母。
(1≤∣s0∣,∣s1∣≤106)
输出描述:
输出一行一个字符串,表示还原后斯汀木上的原字符串。该字符串仅包含大写或小写的拉丁字母。                  
输入
ac!b
acccb
输出
acCb

问题解析

为了方便,我们可以先把没被污染的字符串全部变成小写字母的形式,然后我们再根据第一个字符串中大小写的情况来还原字符串即可。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 2e5 + 50, MOD = 1e9 + 7;

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    string a,b,s,c;
    cin>>a>>b;
    int n=a.size(),m;
    for(auto i:b)
    {
        if(i>='a'&&i<='z')c+=i;
        else 
        {
            c+=(i+32);
            c+=(i+32);
        }
    }
    m=c.size();
    int l=0,r=0;
    while(l<n&&r<m)
    {
        if(a[l]=='?'||(a[l]>='a'&&a[l]<='z'))s+=c[r++];
        else 
        {
            s+=(c[r]-32);
            r+=2;
        }
        l++;
    }
    cout<<s<<endl;
    return 0;
}

I-Darling(Easy.)J-Darling(Hard.)

题目描述

那似乎是比翼鸟,这种鸟天生单翼,须靠雌雄二鸟相互依偎,否则无法翱翔天际,是种有缺陷的生物。但是,不知为何,我却认为这种生活方式是美好的,感受到了其中的美妙。

注:本题与Hard.版唯一的区别在数据范围上

有 n 窝比翼鸟栖息在森林中,同一窝的比翼鸟性别相同。因为天生单翼的原因,他们并不能通过飞翔来寻找另一半,只能通过森林中的 m 条陆路,来寻找彼此。

(n 个点与 m 条边形成了一个无向连通图,每条双向边的长度都为 1)

小袁了解了这种情况,不禁感慨万分。

小袁想知道,一只比翼鸟想要找到另一半,最短需要走多少的路程,即,比翼鸟到异性窝的最短路程。(假设每一窝比翼鸟的数量为无限大)

小袁总共有 ttt 个疑问,每个疑问相互独立。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-aZiQIgcg-1657286971919)(https://uploadfiles.nowcoder.com/images/20220704/0_1656925795549/05266877D72B9576E8D907074DDDA274)]

输入描述:

第一行输入 n,m,t ,分别表示比翼鸟的数量、比翼鸟之间的道路数量,以及小袁疑问的数量。(1≤n,t≤1000,(n−1)≤m≤min(1000,n∗(n−1)2)(n-1)\leq m\leq min(1000,2n∗(n−1)))
第二行输入 nnn 个整数 si,表示每一窝比翼鸟性别,'0' 表示雌性,'1' 表示雄性。(si∈{0,1})
接下去 m 行,每行输入两个正整数 ui,vii,表示 ui 与 vi 之间有一条长为 1 的双向边。(1≤ui,vi≤n,ui!=vi)
接下去 t 行,每行一个正整数 qi,表示询问的比翼鸟在第 qi 窝。(1≤qi≤n)

输出描述:

输出 t 行,每个疑问输出一行一个正整数,表示第 qi 窝的比翼鸟到异性窝的最短路程,如果无法到达异性窝,则输出 ′−1′(不包含引号)。                 
输入
5 5 6
0 1 1 1 1 
1 5
5 2
5 3
2 4
3 2
1
2
3
4
5
1
输出
1
2
2
3
1
1

问题解析

i题数据类型教少,建图之后对于每次询问我们都跑一便bfs来求最近的异性即可。

每次向和自己链接的其它点看去,如果这个点和我们的性别不同,那根据bfs特性,这个就是我们最近的异性,如果周围没有异性,那我们就把和自己相邻的点再送去下一轮bfs,同时步数+1。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 2e5 + 50, MOD = 1e9 + 7;

unordered_map<int,vector<int>>mymap;
signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    int n,m,t,x,y;
    cin>>n>>m>>t;
    vector<int>sex(n+1);
    for(int i=1;i<=n;i++)cin>>sex[i];
    for(int i=0;i<m;i++)
    {
        cin>>x>>y;
        mymap[x].push_back(y);
        mymap[y].push_back(x);
    }
    while(t--)
    {
        int res=0;
        cin>>x;
        queue<int>que;
        que.push(x);
        y=-1;
        vector<int>st(1001);
        while(!que.empty())
        {
            res++;
            int len=que.size();
            for(int i=0;i<len;i++)
            {
                int tt = que.front();
                que.pop();
                for(auto j:mymap[tt])
                {
                    if(st[j]==0)
                    {
                        if(sex[j]!=sex[x])
                        {
                        	//找到了,我们直接结束bfs
                            y=res;
                            break;
                        }
                        else 
                        {
                            que.push(j);
                            st[j]=1;
                        }
                    }
                }
                if(y!=-1)break;
            }
            if(y!=-1)break;
        }
        cout<<y<<endl;
    }
    return 0;
}

至于j题,数据提到了1e6,这样再用上面的方法肯定会t。但还是可以用bfs来写。

我们可以把问题分成两部分:给性别为0的找最近的1,给性别为1的找最近的0。用一个二维数组f来存结果:f[i] [0]表示i到最近的0的距离,f[i] [1]表示i到最近的1的距离。

求哪个性别,就可以先遍历全部的点,把那个性别的点存入队列里,并且把f[i] [当前性别]设为0,因为里它最近的这个性别就是他自己。再进行bfs,我们只bfs到哪些性别和我们不同的点上,如果j是和i相连且性别不同的点,那么就有:

f[j] [当前性别]=f[i] [当前性别]+1;(注意当前性别不是说j的性别,而是我们现在求的性别)

这样在k次询问时,我们可以先判断询问的点是哪个性别,再去对应的数组找结果。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 1e6 + 50, MOD = 1e9 + 7;
unordered_map<int, vector<int>>mymap;
int f[N][2], sex[N];
int n, m, t, x, y;

void bfs(int x)
{
    queue<int>que;
    for(int i=1;i<=n;i++)
        if (sex[i] == x)
        {
            que.push(i);
            f[i][x] = 0;
        }
    while (!que.empty())
    {
        int ans = que.front();
        que.pop();
        for (auto i : mymap[ans])
        {
            if (f[i][x] == -1 && sex[i] != x)
            {
                f[i][x] = f[ans][x] + 1;
                que.push(i);
            }
        }
    }
}

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    cin >> n >> m >> t;
    for (int i = 1; i <= n; i++)cin >> sex[i];
    for (int i = 0; i < m; i++)
    {
        cin >> x >> y;
        mymap[x].push_back(y);
        mymap[y].push_back(x);
    }
    memset(f, -1, sizeof f);
    bfs(0);
    bfs(1);
    while (t--)
    {
        cin >> x;
        if (sex[x])
        {
            cout << f[x][0] << endl;
        }
        else cout << f[x][1] << endl;
    }
    
    return 0;
}

K-小杜返校记

题目描述

小杜因为家乡疫情原因,不能及时返校,可是等他花费 n 元订好返校机票后,学校这边却因疫情原因封校,禁止出入。无可奈何的小杜只能取消机票,在家安心上网课。

已知小杜是在起飞前 t 小时退的票。现在小杜想知道退票并扣除手续费后,自己还能得到多少钱。

以下为小杜机票所属航空公司的自愿退票手续费收费标准表格。

舱位等级航班起飞前 14 天( 336 小时)(含)之前航班起飞前 14 天(不含)至 48 小时(含)航班起飞前 48 小时(不含)至 4 小时(含)航班起飞前 4 小时(不含)至航班起飞后
头等舱免费p1,1%p1,2%p1,3%
商务舱免费p2,1%p2,2%p2,3%
经济舱免费p3,1%p3,2%p3,3%

(根据真实事件改编)

输入描述:
第一行输入两个正整数 n 和 t ,n 和 t 的含义如题目描述所示。
第二行输入一行字符,表示小杜机票的舱位等级。(“First Class”表示头等舱;“Business Class”表示商务舱;“Economy Class”表示经济舱)
接下来输入3行,每行3个正整数。第 i 行第 j 列表示 pi,j。
(1≤n,t≤109,1≤pi,j≤100)
输出描述:
输出一个小数,四舍五入保留 2 位小数,表示小杜退票后还能得到的钱        
输入
742 30
Economy Class
5 5 10
5 10 15
5 20 40
输出
593.60

问题解析

按照舱位和时间找对应的手续费率pi,计算式:n=n(1-pi/100)*。

AC代码

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n'
#define int ll
typedef long long ll;
typedef unsigned long long ull;
typedef pair<ll, ll>PII;
const int N = 2e5 + 50, MOD = 1e9 + 7;

signed main()
{
    ios_base::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);
    vector<vector<double>>v(3,vector<double>(3));
    double money;
    int h=0;
    cin>>money>>h;
    string s,fw;
    cin>>s>>fw;
    for(int i=0;i<3;i++)
        for(int j=0;j<3;j++)
            cin>>v[i][j];
    int x;
    if(s[0]=='F')x=0;
    else if(s[0]=='B')x=1;
    else x=2;
    
    if(h>=336)money=money;
    else if(h>=48)money=money*(1-v[x][0]/100);
    else if(h>=4)money=money*(1-v[x][1]/100);
    else money=money*(1-v[x][2]/100);
    cout << fixed << setprecision(2) << money << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值