“Shopee杯” e起来编程暨武汉大学2020年大学生程序设计大赛决赛(重现赛)
A-A Simple Problem about election
题意
有n个候选人(其中包含ZZZZSGW同学),每个居民都可以给他们投m票,一个居民不能多次对同一个人投票。票数相同的情况下字典序在前的人优先(可以默认ZZZZSGW一定是同票数里最低的)。假设现在除了ZZZZSGW以外的所有人都已经完成了投票并且ZZZZSGW已经知道现在每个人多少票(包括自己),他以最有利于自己排名的方式进行投票,请问他投完之后排名最好是多少?
思路
首先给自己投一票,其次给比自己票数多或者少的人投票都不会对自己的排名有负面影响,但是给同票数的投票会导致排名后退一位。由此,先给所有不同票数的投票,如果还有票没用完,再把剩余的投给同票数的人。
代码
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define pb push_back
using namespace std;
const int N = 1e5 + 10;
int vote[N];
int main()
{
int T;
cin >> T;
while(T--)
{
int n, m;
cin >> n >> m;
m--;
for(int i = 0; i < n; i++)
{
cin >> vote[i];
}
sort(vote + 1, vote + n);
int rnk = 1;
int cnt = 0;
for(int i = 0; i < n; i++)
{
if(vote[i] == vote[0])
{
rnk++;
cnt++;
}
else
{
m--;
if(vote[i] > vote[0])
rnk++;
}
}
if(m < 0)
{
cout << rnk - cnt << endl;
}
else
{
cout << rnk - cnt + m << endl;
}
}
return 0;
}
B-Build the Huoshenshan Hospital
暂无
C-Calculate the Sanity Value
暂无
D-Deploy the medical team
题意
n个人,m个领导,组成一支队伍,队伍人数任意,但是必须有一个领导。请问队伍种数?
思路
m个领导去一个,m种,n个人去或不去都是两种情况,所以是 2 n 2^n 2n种,一共 m × 2 n m \times 2^n m×2n种,用快速幂做一下就行。
代码
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define pb push_back
using namespace std;
const int N = 1e5 + 10;
const int mod = 1e9 + 7;
typedef long long ll;
ll qpow(ll x, ll n)
{
ll ans = 1;
while(n)
{
if(n & 1)
{
ans = (ans * x) % mod;
}
x = x * x % mod;
n >>= 1;
}
return ans;
}
void solve()
{
ll n, m;
cin >> n >> m;
cout << m * qpow(2, n - 1) % mod << endl;
}
int main()
{
int T;
cin >> T;
while(T--)
{
solve();
}
return 0;
}
E-Engage the Medical Workers
暂无
F-Figure out the sequence
题意
给定两个初始字符串 a 1 , a 2 a_1,a_2 a1,a2,第 i i i 个串的递推公式为: a i = a i − 2 + a i − 1 a_i = a_{i - 2} + a_{i - 1} ai=ai−2+ai−1 ,这里的+为拼接。
问第n个串的每个字符出现次数。
思路
最开始想用直接模拟的方法,直接将串接起来,但是MLE了,显然这题不能用如此浅显的方法。
很容易发现,其实每个字符出现的次数随着串的拼接,呈现出的是一个斐波那契函数,这个串的递推公式本身其实也就是斐波那契的递推式,只是换了一种形式。
那么我们线性预处理出最开始的时候每个出现过的字符的数量,也就是预处理每个字符的斐波那契数列的前两位,最后字典序遍历A-Z和a-z,将所有出现过的字符进行斐波那契求解,因为n很小所以直接线性处理就可以。
代码
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define pb push_back
using namespace std;
const int N = 1e5 + 10;
const int mod = 1e9 + 7;
typedef long long ll;
string a, b;
int numa[N];
int numb[N];
int main()
{
cin >> a >> b;
int n;
cin >> n;
for(int i = 0; i < a.length(); i++)
{
numa[(int)a[i]]++;
}
for(int i = 0; i < b.length(); i++)
{
numb[(int)b[i]]++;
}
for(int i = 'A'; i <= 'Z'; i++)
{
if(numa[i] || numb[i])
{
int res = 0;
int pre = numa[i];
int now = numb[i];
int tmp;
for(int i = 2; i < n; i++)
{
tmp = pre;
pre = now;
now = tmp + now;
}
if(n == 1)
now = pre;
if(now)
cout << (char)i << ": " << now << endl;
}
}
for(int i = 'a'; i <= 'z'; i++)
{
if(numa[i] || numb[i])
{
int res = 0;
int pre = numa[i];
int now = numb[i];
int tmp;
for(int i = 2; i < n; i++)
{
tmp = pre;
pre = now;
now = tmp + now;
}
if(n == 1)
now = pre;
if(now)
cout << (char)i << ": " << now << endl;
}
}
return 0;
}
G-Game Strategy
题意
ABC三人分别有长度为n的数组,三个人每轮每人移除一个数,直到大家的数组都只剩一个数字,此时将剩下的三个数字加起来得到结果。A的目标是让结果尽可能大,B的目标是让结果尽可能小,C的目标是让结果尽可能接近0,若C有多种可选的情况,ta会选择让结果大于0的那个。问最终结果是多少?
思路
开始以为是A一直删掉最大,B一直删掉最小,C只需要判断AB最后剩下的那两个数就行,样例直接否决了我。
- 首先C肯定根据A+B的值,对自己保留的数字进行枚举,选择能让答案最接近0且所有可行答案中最大的那个;
- 其次,B对于A的每种保留选择,ta先对于自己所保留的数字进行枚举,判断保留当前数字时C会选择哪一个,此时的结果是多少,从所有的结果中选择最小的;
- 最后,A也对自己保留的数字进行枚举,判断每种情况B和C会如何选,选择其中能令结果最大的。
这可能就是螳螂捕蝉黄雀在后。
由此,我们只需要进行一个 O ( N 3 ) O(N^3) O(N3) 的暴力枚举,就能得出最终答案。
代码
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define pb push_back
using namespace std;
const int N = 1e5 + 10;
const int mod = 1e9 + 7;
typedef long long ll;
int a[N], b[N], c[N];
int main()
{
int n;
cin >> n;
for(int i = 0; i < n; i++)
{
cin >> a[i];
}
for(int i = 0; i < n; i++)
{
cin >> b[i];
}
for(int i = 0; i < n; i++)
{
cin >> c[i];
}
ll maxx = -INF;
for(int i = 0; i < n; i++)
{
ll minn = INF;
for(int j = 0; j < n; j++)
{
ll abss = INF;
for(int k = 0; k < n; k++)
{
if(abs(a[i] + b[j] + c[k]) < abs(abss) ||
(abs(a[i] + b[j] + c[k]) == abs(abss) &&
a[i] + b[j] + c[k] > abss))
abss = a[i] + b[j] + c[k];
}
minn = min(minn, abss);
}
maxx = max(maxx, minn);
}
cout << maxx << endl;
return 0;
}
H-Hinnjaku
题意
J O J O JOJO JOJO和 D I O DIO DIO对打
J O J O JOJO JOJO言: o r a o r a o r a o r a oraoraoraora oraoraoraora
D I O DIO DIO言: m u d a m u d a m u d a mudamudamuda mudamudamuda
他们每说完一句攻击,就对对方造成一点伤害。
显然, m u d a muda muda比 o r a ora ora长,所以 d i o dio dio占劣势。
但是两个人还可以使出 z a w a l u d u o zawaluduo zawaluduo,使出该招时对方正在进行的攻击被打断,并且对方HP直接清零。同时使出 z a w a l u d u o zawaluduo zawaluduo的时候,认定 D I O DIO DIO的优先级更高。
最后剩余血量较多的胜利,血量相等或者都是 0 0 0 平手。请认定每局胜负。
思路
硬核模拟。所有该翻译的条件都在上面了,直接做就行(虽然但是我因为不仔细wa了2次)
代码
#include <bits/stdc++.h>
#define INF 0x3f3f3f3f
#define pb push_back
using namespace std;
const int N = 2e5 + 10;
char dio[N];
char jojo[N];
char ora[] = "ora";
char muda[] = "muda";
char zawaluduo[] = "zawaluduo";
int main()
{
int T;
cin >> T;
while(T--)
{
int n;
int hpj, hpd;
int j = 0, d = 0, jk = 0, dk = 0;
cin >> n >> hpj;
hpd = hpj;
cin >> jojo >> dio;
for(int i = 0; i < n && hpj > 0 && hpd > 0; i++)
{
if(zawaluduo[dk] != dio[i])
{
dk = 0;
}
if(zawaluduo[dk] == dio[i])//要重新匹配所以不能用else
{
dk++;
if(dk == 9)
{
hpj = 0;
continue;
}
}
if(zawaluduo[jk] != jojo[i])
{
jk = 0;
}
if(zawaluduo[jk] == jojo[i])
{
jk++;
if(jk == 9)
{
hpd = 0;
continue;
}
}
if(ora[j] != jojo[i])
{
j = 0;
}
if(ora[j] == jojo[i])
{
j++;
if(j == 3)
{
j = 0;
hpd--;
}
}
if(muda[d] != dio[i])
{
d = 0;
}
if(muda[d] == dio[i])
{
d++;
if(d == 4)
{
d = 0;
hpj--;
}
}
}
if(hpj > hpd)
{
cout << "Wryyyyy" << endl;
}
else if(hpj < hpd)
{
cout << "Hinnjaku" << endl;
}
else
{
cout << "Kono Dio da" << endl;
}
}
return 0;
}
I-Interesting Matrix Problem
暂无
J-Jogging along the Yangtze River
暂无
总结
这次我贡献太小了,全程有点跟不上队友的思路,希望下次能多点贡献
打疫苗的日子是真的困到魂都飘了,昨天凡是我做的题都是错好几遍才过,今天重新看了一遍真的觉得不难,做出来的7道题只有I和J相对难度大一些,我的队友实在太强了(嗯