[比赛|考试]nowcoder 小白月赛7
牛客小白月赛7
比赛地址。本次比赛我切了8道(ACM赛制),rank(20)。
反思:刚入手ACM赛,光追求刺激了,没有总结ACM赛制的经验。是应该多提交》。。还是少提交。。。小白赛还有两道不会的题呢。(其实是懒得推了)。所以以后刷题提手速,提脑速,提高做题时的紧张感(膜拜石室中学某大佬)。在打OI赛因为没有实时的rank总会不紧张。。。(当然OI赛没必要太紧张,要认真,以稳为准)在OI阶段还是要以OI赛制为主,ACM赛制只是尝尝鲜罢了。
明天还有一场tg组的比赛,希望能把暴力分拿满,正解写出。
以下是部分题解
A.送分题
做水题就是在浪费时间,但是一场比赛要是没有送分的签到题,大家的比赛体验就会很差。为了优化你的比赛体验又不浪费你的读题时间,我并不打算给你很复杂的故事背景,你只需要复制下面的代码并选择正确的语言提交即可通过此题。
#include<iostream>
using namespace std;
long long f(long long n)
{
if (n < 20180001)
return n + 2017;
return f(f(n - 2018));
}
int main()
{
long long n;
cin >> n;
cout << f(n) << endl;
return 0;
}
题目描述tmd有误,直接复制代码无法通过本题。。。
找规律发现当\(n<20180000\)时,都是n+2017,否则都是20182017。代码如下
#include<bits/stdc++.h>
using namespace std;
int main()
{
long long n;
cin >> n;
if ( n >= 20180000)
cout << 20180000 + 2017 <<endl;
else
cout << n + 2017 << endl;
return 0;
}
B.自杀游戏
Alice和Bob产生了不可调节的矛盾,于是他们相约一起玩一个自杀游戏,输的人就会从这个世界上消失。 游戏开始时,Alice手上拿着一个定时炸弹,炸弹有个倒计时t。炸弹在t=0时刻会爆炸,此时手上拿着炸弹的人会从这个世界上消失。为了增加游戏乐趣,他们约定每个人拿到炸弹后可以选择将炸弹的时间调快d秒(d ∈ [a,b]),或者不调。每次交换炸弹会消耗1秒(假设调节炸弹时间不需要消耗时间)。 问题来了,如果双方都足够聪明,谁会活下去呢?输入t a b输出谁会存活。
令f[i]表示炸弹有i秒时候先手是否存活,f[i]可以由f[i-1],f[i-b-1]到f[i-a-1]内的数转移,如果这些数里有数是0那么就f[i]=1,否则f[i]=0。(SG函数)本来想写个树状数组维护但是写炸了,然后看数据范围发现暴力能过。
#include <bits/stdc++.h>
using namespace std;
int c[100010], t, a, b;
int main()
{
scanf("%d%d%d", &t, &a, &b);
for (int i = 1; i <= t; i++)
if (c[i - 1] == 0)
c[i] = 1;
else
for (int j = max(0, i - b - 1); j <= max(-1, i - a - 1); j++)
if (c[j] == 0)
{
c[i] = 1;
break;
}
printf("%s\n", (c[t]) ? "Alice" : "Bob");
return 0;
}
C.谁是神射手
有一天,MWH突然来了兴致,想和CSL比比谁枪法好。于是他们找来了一个瓶子,比比看谁先打中这个瓶子。 给定MWH的命中率\(\alpha\%\)和CSL的命中率\(\beta\%\)。 两人轮流射击,MWH先手,问谁获胜的概率大?设\(f(\alpha,\beta)\)代表先手获胜的概率(这里认为他们俩是[0,1]的实数),那么容易得到式子:\(f(\alpha,\beta)=\alpha+(1-\alpha)*(1-\beta)*f(\alpha,\beta)\),那么我们乱推推就能得到\((-\alpha*\beta+\alpha+\beta)f(\alpha,\beta)=\alpha\),那么\(\displaystyle f(\alpha,\beta)=\frac{\alpha}{-\alpha*\beta+\alpha+\beta}\)。令\(f(\alpha,\beta)=0.5\)得到\(-\alpha*\beta+\alpha+\beta=2\alpha\),然后再乱推推就得到就像程序中的结论。()懒得推了
#include <bits/stdc++.h>
using namespace std;
int alpha, beta;
double work(double a, double b)
{
return a + (1 - a) * (1 - b) * work(a, b);
}
int main()
{
cin >> alpha >> beta;
int l = 100 * alpha;
int r = 100 * beta - alpha * beta;
if (l < r)
cout << "CSL" << endl;
if (l == r)
cout << "equal" << endl;
if (l > r)
cout << "MWH" << endl;
return 0;
}
D.明七暗七
今天是个特殊的日子,CSL和他的小伙伴们围坐在一张桌子上玩起了明七暗七的游戏。游戏规则是这样的: 一个人报出一个起始数,接下来按照逆时针的顺序轮流报数,如果碰到数是7的倍数或含有7,则拍手,下一个人接着报数。直到有一个人报错了数字或者没有及时拍手为止。 玩游戏嘛,当然得有惩罚。这么简单的游戏对CSL的学霸小伙伴而言实在是太无脑了,轻轻松松数到上万根本不在话下。但是对于数学是体育老师教的CSL来说,实在是太难了。快帮他算算什么时候应该拍手吧。
不会做
E.Applese的超能力
Applese有个神奇的能力,TA可以把m个硬币融合成1个硬币,是不是很厉害。现在Applese有n个硬币,TA想把这个n个硬币融合成1个,请问他能完成吗?
考虑Huffman编码时补全节点的情况:\(n\equiv1\pmod{m-1}\)。所以只需要判断这个式子是否成立就行了。
注意特殊的情况:m=1.此时你是无法融合的,所以当n=1输出Yes,否则No
m=2.此时你可以xjb融合,最后肯定能融合出1个硬币。直接输出Yes
#include <bits/stdc++.h>
using namespace std;
int main()
{
long long n, m;
cin >> n >> m;
if (m == 1)
cout << ((n == 1) ? "Yes" : "No") << endl;
else if (m == 2)
cout << "Yes" << endl;
else
cout << ((n % (m - 1) == 1) ? "Yes" : "No") << endl;
return 0;
}
F.BFS
Bob在学习了DFS后,自己又发明了一种新的搜(luan)索(gao)方法,叫做BFS(Bobby First Search)。 这种搜索被定义为:在一个字符串中,从前向后查找第一个子串"Bob"出现的位置。(不区分大小写)
用STL水过。先转换一下大小写,然后直接调用find即可。(偷个懒写个c++11的auto)
#include <bits/stdc++.h>
using namespace std;
int main()
{
string str;
cin >> str;
for (string::iterator i = str.begin(); i != str.end(); i++)
{
if (isupper(*i))
(*i) = tolower(*i);
}
auto res = str.find("bob");
if (res == string::npos)
cout << -1 << endl;
else
cout << res << endl;
return 0;
}
G.CSL分苹果
CSL手上有n个苹果,第i个苹果的质量是wi,现在他想把这些苹果分给他的好朋友wavator和tokitsukaze。但是CSL为了不让他们打架,根据质量决定尽量地均分成两堆分给他们。现在CSL想知道到底给每个人分多少质量的苹果。注意:苹果不能劈开来,并且如果不能正好均分,tokitsukaze小姐姐会拿到重的那一堆。
dp。令f[i]
表示是否能组成质量为i的,每次输入就转移一下就行了。
从总质量/2开始枚举(向上/向下都行),直到找到一个f[i]\neq0
输出解就行。
H.CSL的校园卡
今天是阳光明媚,晴空万里的一天,CSL早早就高兴地起床走出寝室到校园里转悠。 但是,等到他回来的时候,发现他的校园卡不见了,于是他需要走遍校园寻找它的校园卡。CSL想要尽快地找回他掉的校园卡,于是便求助于OneDay帮他一起找。 OneDay和CSL在同一已知的地点出发,并以相同的速度(1格/秒)搜索校园,试求两人走遍校园的最短时间。输入描述:第一行为两个整数n,m(1 ≤ n, m ≤ 4),表示地图的大小。接下来是n行m列的地图:X表示障碍物,S表示起点,O表示空地。障碍物不能直接经过,数据保证所有空地是可达的,起点有且只有一个。输出描述:输出一个整数表示两人共同走遍校园所需的最少时间。
不会
I.新建 Microsoft Office Word 文档
CSL正在学习《计算机办公自动化》文件的建立与删除。 CSL发现,当他新建一个word文档时,会得到一个名为"新建 Microsoft Office Word 文档.doc"的文件,再新建一个,则名为"新建 Microsoft Office Word 文档(2).doc",再新建,便是"新建 Microsoft Office Word 文档(3).doc"。不断新建,编号不断递增。倘若他已经新建了三个文档,然后删除了"新建 Microsoft Office Word 文档(2).doc",再新建一个就又会得到一个"新建 Microsoft Office Word 文档(2).doc"。 严格来说,Windows在每次新建文档时,都会选取一个与已有文件编号不重复的最小正整数作为新文档的编号。 现在,请你编程模拟以上过程,支持以下两种操作: New:新建一个word文档,反馈新建的文档的编号; Delete id:删除一个编号为id的word文档,反馈删除是否成功。 初始时一个文件都没有,"新建 Microsoft Office Word 文档.doc"的编号算作1。第一行一个正整数n表示操作次数,接下来n行,每行表示一个操作。若该行为"New",则表示新建,为:Delete id"则表示要删除编号为id的文档,其中id为一个正整数。操作按输入顺序依次进行。操作次数不超过100000,删除编号的数值不超过100000。输出描述:对于输入的每一个操作,输出其反馈结果。对于新建操作,输出新建的文档的编号;对于删除操作,反馈删除是否成功:如果删除的文件存在,则删除成功,输出"Successful",否则输出"Failed"。
我的思路是用一个平衡树(stl的set)维护当前存在的文件,用一个小根堆(stl的priority_queue)维护被删除的文件。
每次新建文件,在小根堆查询是否有数,如果没有就新开一个数。
每次删除文件,在平衡树判断是否存在,如果存在就把文件从平衡树扔到小根堆里,否则输出failed
#include <bits/stdc++.h>
using namespace std;
set<int> s;
priority_queue<int, vector<int>, greater<int> > q;
int main()
{
int n;
cin >> n;
string str;
int opd;
int ptr = 0;
for (int i = 1; i <= n; i++)
{
cin >> str;
if (str == "New")
{
if (!q.empty())
{
int x = q.top();
q.pop();
s.insert(x);
cout << x << endl;
}
else
{
s.insert(++ptr);
cout << ptr << endl;
}
}
if (str == "Delete")
{
cin >> opd;
if (s.find(opd) != s.end())
{
s.erase(opd);
q.push(opd);
cout << "Successful" << endl;
}
else
{
cout << "Failed" << endl;
}
}
}
return 0;
}
J.方格填色
给一个m x n的方格,Applese想要给方格填上颜色,每个格子可以是黑色或者白色。他要求左右相邻两格不能同为白色且相邻两列不能全为黑色。 求满足条件的方案数。(1 ≤ m ≤ 5, 1 ≤ n ≤ 10的18次方)。
令f[i][j]
表示某一长度的序列,以状态为i开头,状态为j结尾的序列的情况数量。(状态在[0,2^m)之间。)
然后呢可以\(O(n*(2^m)^2)\)递推一下,但是因为这个递推满足结合律,可以用快速幂加速。(不知道这个叫不叫矩阵快速幂),但是一次计算是\(O((2^m)^4)\)的????反正我tmAC了。。。
#include <bits/stdc++.h>
#define p 1000000007
using namespace std;
struct statement
{
long long f[32][32];
statement(){memset(f, 0, sizeof(f));}
};
long long maxn;
statement operator*(const statement &a, const statement &b)
{
statement ans;
for (int lmid = 0; lmid <= maxn; lmid++)
for (int rmid = 0; rmid <= maxn; rmid++)
{
if ((lmid != 0 || rmid != 0) && ((lmid & rmid) == 0))
{
for (int l = 0; l <= maxn; l++)
for (int r = 0; r <= maxn; r++)
{
ans.f[l][r] += 1LL * a.f[l][lmid] * b.f[rmid][r] % p;
ans.f[l][r] %= p;
}
}
}
return ans;
}
statement fast_pow(statement x, long long y)
{
statement ans;
for (int i = 0; i <= maxn; i++)
ans.f[i][i] = 1;
while (y > 0)
{
if (y & 1)
ans = ans * x;
x = x * x;
y >>= 1;
}
return ans;
}
int main()
{
long long n, m;
cin >> m >> n;
maxn = (1LL << m) - 1;
statement ans;
for (int i = 0; i <= maxn; i++)
ans.f[i][i] = 1;
ans = fast_pow(ans, n - 1);
long long res = 0;
for (int l = 0; l <= maxn; l++)
for (int r = 0; r <= maxn; r++)
(res += ans.f[l][r]) %= p;
cout << res << endl;
return 0;
}