比赛链接:牛客竞赛_ACM/NOI/CSP/CCPC/ICPC算法编程高难度练习赛_牛客竞赛OJ
文章目录
- [1. 小红的对错判断](#1. 小红的对错判断)
-
- [1.1 题目描述](#1.1 题目描述)
- [1.2 思路](#1.2 思路)
- [1.3 代码](#1.3 代码)
- [2. 小红的幂表达](#2. 小红的幂表达)
-
- [2.1 题目描述](#2.1 题目描述)
- [2.2 思路](#2.2 思路)
- 2.3代码
- [3. 小红的前缀询问](#3. 小红的前缀询问)
-
- [3.1 题目描述](#3.1 题目描述)
- [3.2 思路](#3.2 思路)
- [3.3 代码](#3.3 代码)
- 4.小红和小紫的博弈游戏
-
- [4.1 题目描述](#4.1 题目描述)
- [4.2 思路(非证明)](#4.2 思路(非证明))
- [4.3 代码](#4.3 代码)
1. 小红的对错判断
1.1 题目描述
小红在判题的时候,经常发现选手把"Yes"输出成"YES"或者"yes",她希望写一个spj(special judge)来判断选手是否输出了"Yes"。你能帮帮她吗?
1.2 思路
判断三个字符是否是相对应的字符就可以了。
1.3 代码
cpp
#include <iostream>
#include <string>
using namespace std;
int main()
{
string s;
cin >> s;
if (s[0] == 'y' || s[0] == 'Y' && s[1] == 'e' || s[1] == 'E' && s[2] == 's' || s[2] == 'S')
cout << "accept";
else
cout << "wrong answer";
return 0;
}
2. 小红的幂表达
2.1 题目描述
小红拿到了一个正整数,请你帮小红将其表达为(a^b)的形式。
2.2 思路
因为题目要求我们按指数从小到大输出。那么我们的a肯定就是从大到小了。为此我们可以用一个数从大到小来表示底数a。再用一个数字来表示幂b。渐渐的增大幂b,直到(a^b)大于等于x。最后我们只需要判断一下(a^b)是否等于x,如果相等就说明这个a,b合法。
小细节:在(a^b)的增大过程中,可能会溢出。为此我们需要开long long.
2.3代码
cpp
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int x;
void solve()
{
printf("%d\n",x);
for(int i = x;i>=2;--i)
{
ll tmp = 1,num = 0;
while(tmp<x)
{
tmp*=i;
num+=1;
}
if(tmp == x)
printf("=%d^%d\n",i,num);
}
}
int main()
{
cin>>x;
solve();
return 0;
}
3. 小红的前缀询问
3.1 题目描述
小红拿到了一个数组,她有若干次询问,每次询问一个前缀内有多少对相同的数。你能帮帮她吗?
如果存在i,j,1<=i<j<=n,且ai=aj,那么(ai,aj)就是一对相同的数对。只要下标不同,就是不同的数对。
3.2 思路
超级常见的前缀和。我们创建一个数组prev来存储前缀和。再创建一个哈希表来存储该元素在目前为止有多少个相同元素。一旦当前元素的数目(c)大于1就让prev[i] 等于前一个prev在加上c-1。
为什么是(c-1)呢?新加的一个元素数目可以和前面所以相同元素配对一次,组成相同元素组。
注意:要开long long不然prev数组会溢出。
3.3 代码
cpp
#include <bits/stdc++.h>
#define ll long long
using namespace std;
int main()
{
int n;
cin >> n;
vector<int> v(n);
for (int i = 0; i < n; ++i) cin >> v[i];
vector<ll> prev(n);
unordered_map<int, int> cnt;
cnt[v[0]] = 1;
for (int i = 1; i < n; ++i)
{
cnt[v[i]] += 1;
int c = cnt[v[i]];
if (c > 1)
{
prev[i] = prev[i-1] + c-1;
}
else prev[i] = prev[i - 1];
}
for (int i = 0; i < n; ++i) cout << prev[i] << ' ';
return 0;
}
4.小红和小紫的博弈游戏
4.1 题目描述
小红和小紫拿到了一个2*2的矩阵,她们准备在这个矩阵上玩一个博弈游戏。
游戏的规则是:两人轮流操作,每次操作时选择两个相邻的正整数,使它们同时减1。谁先无法操作谁就输了。
小红先手操作,她想知道,两人都使用最优策略的情况下,谁将获得最终胜利?
4.2 思路(非证明)
既然存在从开始就能知道谁赢的方法,那么就不可以确定比赛的次数了吗?毕竟比赛的胜利条件和比赛的次数是存在关系的。
为此我们可以先随便写一个2*2的矩阵。
就以这个矩阵为例子。假设可以先从每一次都选第一行,直到减到不合法在转到其他行。
该次的遍历历程是先第一行,再第二行。
该次遍历的历程是先左一列,再上一行,再右一列。同样也是11次。
那么我们大胆猜测!无论怎么选择最后的次数一定是相同的。这样的话,我们只需要来判断最后一次是谁来执行就可以判断谁会是赢家。
按照我们图中的情况,表示的是除去小红第一次操作后。当次数为单数的情况下小红获胜。反之小紫获胜。
4.3 代码
cpp
#include <bits/stdc++.h>
using namespace std;
#define ll long long
int t;
int arr[3][3];
int count_ = 0;
int func(int& a, int& b)
{
int minCount = min(a, b);
a -= minCount; b -= minCount;
return minCount;
}
void solve()
{
//寻找第一行最小的数字
count_ += func(arr[0][0], arr[0][1]);
if (arr[0][0] == arr[0][1]) //第一行已经为0
{
count_ += func(arr[1][0], arr[1][1]);
}
else if (arr[0][0] == 0)//第一行左边为0
{
count_ += func(arr[0][1], arr[1][1]);
if (arr[0][1] == arr[1][1])
return;
else if (arr[0][1] == 0)
{
count_ += func(arr[1][0], arr[1][1]);
return;
}
else return;
}
else
{
count_ += func(arr[0][0], arr[1][0]);
if (arr[0][0] == arr[1][0]) return;
else if (arr[0][0] == 0)
{
count_ += func(arr[1][0], arr[1][1]);
return;
}
else return;
}
}
int main()
{
cin >> t;
while (t--)
{
count_ = 0;
for (int i = 0; i < 2; ++i)
for (int j = 0; j < 2; ++j)
cin >> arr[i][j];
solve();
if ((count_ ) % 2 == 1) cout << "kou" << endl;
else cout << "yukari" << endl;
}
return 0;
}