北华大学计算机程序设计算法提高训练营个人赛(无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=1∑n−1(ai+1−ai)
每次操作可以选择一个 i,满足
1
≤
i
<
n
1≤i<n
1≤i<n
,并交换
a
i
和
a
i
+
1
ai 和 ai+1
ai和ai+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 点的经验值。小袁不想浪费经验材料。
原神中有三种可以加经验的材料:
- 大英雄的经验:20000点;
- 冒险者的经验:5000 点;
- 流浪者的经验: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 次)以下的操作:
- 将相邻两个小写字符合并成一个对应的大写字符,如 “aa” -> “A”;
- 将一个大写字符拆分成两个对应的相邻的小写字符,如 “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;
}