[NOIP2003 普及组] 乒乓球
题目背景
国际乒联现在主席沙拉拉自从上任以来就立志于推行一系列改革,以推动乒乓球运动在全球的普及。其中 11 11 11 分制改革引起了很大的争议,有一部分球员因为无法适应新规则只能选择退役。华华就是其中一位,他退役之后走上了乒乓球研究工作,意图弄明白 11 11 11 分制和 21 21 21 分制对选手的不同影响。在开展他的研究之前,他首先需要对他多年比赛的统计数据进行一些分析,所以需要你的帮忙。
题目描述
华华通过以下方式进行分析,首先将比赛每个球的胜负列成一张表,然后分别计算在 11 11 11 分制和 21 21 21 分制下,双方的比赛结果(截至记录末尾)。
比如现在有这么一份记录,(其中 W \texttt W W 表示华华获得一分, L \texttt L L 表示华华对手获得一分):
WWWWWWWWWWWWWWWWWWWWWWLW \texttt{WWWWWWWWWWWWWWWWWWWWWWLW} WWWWWWWWWWWWWWWWWWWWWWLW
在 11 11 11 分制下,此时比赛的结果是华华第一局 11 11 11 比 0 0 0 获胜,第二局 11 11 11 比 0 0 0 获胜,正在进行第三局,当前比分 1 1 1 比 1 1 1。而在 21 21 21 分制下,此时比赛结果是华华第一局 21 21 21 比 0 0 0 获胜,正在进行第二局,比分 2 2 2 比 1 1 1。如果一局比赛刚开始,则此时比分为 0 0 0 比 0 0 0。直到分差大于或者等于 2 2 2,才一局结束。
你的程序就是要对于一系列比赛信息的输入( WL \texttt{WL} WL 形式),输出正确的结果。
输入格式
每个输入文件包含若干行字符串,字符串有大写的 W \texttt W W 、 L \texttt L L 和 E \texttt E E 组成。其中 E \texttt E E 表示比赛信息结束,程序应该忽略 E \texttt E E 之后的所有内容。
输出格式
输出由两部分组成,每部分有若干行,每一行对应一局比赛的比分(按比赛信息输入顺序)。其中第一部分是 11 11 11 分制下的结果,第二部分是 21 21 21 分制下的结果,两部分之间由一个空行分隔。
样例 #1
样例输入 #1
WWWWWWWWWWWWWWWWWWWW
WWLWE
样例输出 #1
11:0
11:0
1:1
21:0
2:1
提示
每行至多 25 25 25 个字母,最多有 2500 2500 2500 行。
(注:事实上有一个测试点有 2501 2501 2501 行数据。)
【题目来源】
NOIP 2003 普及组第一题
#include <iostream>
#include <string>
#include <math.h>
using namespace std;
//这道题没有什么难的,典型的堆积木题
//按部就班去做就行
//但是要注意在读到E后将现有的比分输出
int w[100000], l[100000]; //存放比分情况
int p = 0, p1 = 1;
void myprintf() //打印
{
for (int i = 0; i <= p; i += 2) //偶数存11制
{
cout << w[i] << ':' << l[i] << endl;
}
cout << endl;
for (int i = 1; i <= p1; i += 2) //奇数存22制
{
cout << w[i] << ':' << l[i] << endl;
}
}
int main()
{
string in;
while (cin >> in)
{
for (int i = 0; i < in.size(); i++)
{
if (in[i] == 'W')
{
w[p]++;
w[p1]++;
}
if (in[i] == 'L')
{
l[p]++;
l[p1]++;
}
if (in[i] == 'E')
{
myprintf();
return 0;
}
if (abs(w[p] - l[p]) >= 2&& (w[p] >= 11 || l[p] >= 11))
{
p+=2;
}
if (abs(w[p1] - l[p1]) >= 2 && (w[p1] >= 21 || l[p1] >= 21))
{
p1+=2;
}
}
}
return 0;
}
################################分割##################################
[NOIP2015 普及组] 扫雷游戏
题目背景
NOIP2015 普及组 T2
题目描述
扫雷游戏是一款十分经典的单机小游戏。在 n n n 行 m m m 列的雷区中有一些格子含有地雷(称之为地雷格),其他格子不含地雷(称之为非地雷格)。玩家翻开一个非地雷格时,该格将会出现一个数字——提示周围格子中有多少个是地雷格。游戏的目标是在不翻出任何地雷格的条件下,找出所有的非地雷格。
现在给出 n n n 行 m m m 列的雷区中的地雷分布,要求计算出每个非地雷格周围的地雷格数。
注:一个格子的周围格子包括其上、下、左、右、左上、右上、左下、右下八个方向上与之直接相邻的格子。
输入格式
第一行是用一个空格隔开的两个整数 n n n 和 m m m,分别表示雷区的行数和列数。
接下来 n n n 行,每行 m m m 个字符,描述了雷区中的地雷分布情况。字符 * \texttt{*} * 表示相应格子是地雷格,字符 ? \texttt{?} ? 表示相应格子是非地雷格。相邻字符之间无分隔符。
输出格式
输出文件包含 n n n 行,每行 m m m 个字符,描述整个雷区。用 * \texttt{*} * 表示地雷格,用周围的地雷个数表示非地雷格。相邻字符之间无分隔符。
样例 #1
样例输入 #1
3 3
*??
???
?*?
样例输出 #1
*10
221
1*1
样例 #2
样例输入 #2
2 3
?*?
*??
样例输出 #2
2*1
*21
提示
对于 100 % 100\% 100%的数据, 1 ≤ n ≤ 100 , 1 ≤ m ≤ 100 1≤n≤100, 1≤m≤100 1≤n≤100,1≤m≤100。
#include <iostream>
using namespace std;
//堆积木的题,但是想出来了一个很搞的方法,
//通过差值来计算雷数,没什么用。
char boom[110][110] = {0};
char out[110][110];
int cal(int x, int y)
{
int num = 0, p = 9;
for (int i = x - 1; i <= x + 1; i++)
{
for (int j = y - 1; j <= y + 1; j++)
{
if (boom[i][j] == 0) p--;
else num += boom[i][j];
}
}
num = (63*p - num)/21;
return num;
}
int main()
{
int l, c;
cin >> l >> c;
for (int i = 1; i <= l; i++) cin >> &boom[i][1]; //输入完成
for (int i = 1; i <= l; i++)
{
for (int j = 1; j <= c; j++)
{
if (boom[i][j] == '?')
{
char c = '0';
c += cal(i, j);
out[i][j] = c;
}
else out[i][j] = '*';
}
}
for (int i = 1; i <= l; i++)
{
for (int j = 1; j <= c; j++)
{
printf("%c", out[i][j]);
}
printf("\n");
}
return 0;
}
################################分割##################################
[NOIP2016 提高组] 玩具谜题
题目背景
NOIP2016 提高组 D1T1
题目描述
小南有一套可爱的玩具小人,它们各有不同的职业。
有一天,这些玩具小人把小南的眼镜藏了起来。小南发现玩具小人们围成了一个圈,它们有的面朝圈内,有的面朝圈外。如下图:
[外链图片转存中…(img-fabzYpX3-1717039036389)]
这时 singer 告诉小南一个谜题:“眼镜藏在我左数第 3 3 3 个玩具小人的右数第 1 1 1 个玩具小人的左数第 2 2 2 个玩具小人那里。”
小南发现,这个谜题中玩具小人的朝向非常关键,因为朝内和朝外的玩具小人的左右方向是相反的:面朝圈内的玩具小人,它的左边是顺时针方向,右边是逆时针方向;而面向圈外的玩具小人,它的左边是逆时针方向,右边是顺时针方向。
小南一边艰难地辨认着玩具小人,一边数着:
singer 朝内,左数第 3 3 3 个是 archer。
archer 朝外,右数第 1 1 1 个是 thinker。
thinker 朝外,左数第 2 2 2 个是 writer。
所以眼镜藏在 writer 这里!
虽然成功找回了眼镜,但小南并没有放心。如果下次有更多的玩具小人藏他的眼镜,或是谜题的长度更长,他可能就无法找到眼镜了。所以小南希望你写程序帮他解决类似的谜题。这样的谜題具体可以描述为:
有 n n n 个玩具小人围成一圈,已知它们的职业和朝向。现在第 1 1 1 个玩具小人告诉小南一个包含 m m m 条指令的谜題,其中第 z z z 条指令形如“向左数/右数第 s s s 个玩具小人”。你需要输出依次数完这些指令后,到达的玩具小人的职业。
输入格式
输入的第一行包含两个正整数 n , m n,m n,m,表示玩具小人的个数和指令的条数。
接下来 n n n 行,每行包含一个整数和一个字符串,以逆时针为顺序给出每个玩具小人的朝向和职业。其中 0 0 0 表示朝向圈内, 1 1 1 表示朝向圈外。保证不会出现其他的数。字符串长度不超过 10 10 10 且仅由英文字母构成,字符串不为空,并且字符串两两不同。整数和字符串之间用一个空格隔开。
接下来 m m m 行,其中第 i i i 行包含两个整数 a i , s i a_i,s_i ai,si,表示第 i i i 条指令。若 a i = 0 a_i=0 ai=0,表示向左数 s i s_i si 个人;若 a i = 1 a_i=1 ai=1,表示向右数 s i s_i si 个人。 保证 a i a_i ai 不会出现其他的数, 1 ≤ s i < n 1 \le s_i < n 1≤si<n。
输出格式
输出一个字符串,表示从第一个读入的小人开始,依次数完 m m m 条指令后到达的小人的职业。
样例 #1
样例输入 #1
7 3
0 singer
0 reader
0 mengbier
1 thinker
1 archer
0 writer
1 mogician
0 3
1 1
0 2
样例输出 #1
writer
样例 #2
样例输入 #2
10 10
1 C
0 r
0 P
1 d
1 e
1 m
1 t
1 y
1 u
0 V
1 7
1 1
1 4
0 5
0 3
0 1
1 6
1 2
0 8
0 4
样例输出 #2
y
提示
样例 1 说明
这组数据就是【题目描述】中提到的例子。
子任务
子任务会给出部分测试数据的特点。如果你在解决题目中遇到了困难,可以尝试只解决一部分测试数据。
每个测试点的数据规模及特点如下表:
其中一些简写的列意义如下:
-
全朝内:若为 √ \surd √,表示该测试点保证所有的玩具小人都朝向圈内;
-
全左数:若为 √ \surd √,表示该测试点保证所有的指令都向左数,即对任意的 1 ≤ z ≤ m , a i = 0 1\leq z\leq m, a_i=0 1≤z≤m,ai=0;
-
s = 1 s=1 s=1:若为 √ \surd √,表示该测试点保证所有的指令都只数 1 1 1 个,即对任意的 1 ≤ z ≤ m , s i = 1 1\leq z\leq m,s_i=1 1≤z≤m,si=1;
职业长度为 1 1 1:若为 √ \surd √,表示该测试点保证所有玩具小人的职业一定是一个长度为 1 1 1 的字符串。
#include <iostream>
#include <vector>
//思路
//通过分析可以知道,朝向圈内的左边是减少 朝向圈外的左边是增加
//映射到题中的0,1就是相同就减少,不同就增加
using namespace std;
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);//减少cin和cout浪费的时间
pair<bool, string> p;
vector <pair<bool, string>> v;
int people, work;
cin >> people >> work;
while (people--)
{
cin >> p.first >> p.second;
v.push_back(p);
}
int point = 0;
while (work--)
{
int d, n;
cin >> d >> n;
if (v[point].first == d) point -= n;
else point += n;
if (point < 0) while (point < 0) point += v.size();
if (point >= v.size()) while (point >= v.size()) point -= v.size();
}
cout << v[point].second << endl;
return 0;
}
################################分割##################################
A+B Problem(高精)
题目描述
高精度加法,相当于 a+b problem,不用考虑负数。
输入格式
分两行输入。 a , b ≤ 1 0 500 a,b \leq 10^{500} a,b≤10500。
输出格式
输出只有一行,代表 a + b a+b a+b 的值。
样例 #1
样例输入 #1
1
1
样例输出 #1
2
样例 #2
样例输入 #2
1001
9099
样例输出 #2
10100
提示
20 % 20\% 20% 的测试数据, 0 ≤ a , b ≤ 1 0 9 0\le a,b \le10^9 0≤a,b≤109;
40 % 40\% 40% 的测试数据, 0 ≤ a , b ≤ 1 0 18 0\le a,b \le10^{18} 0≤a,b≤1018。
#include <iostream>
using namespace std;
//思路就是将人类的加法思维用代码实现
int a[510], b[510],sum[510];
int main()
{
string ina, inb;
cin >> ina >> inb;
for (int i = ina.size() - 1; i >= 0; i--) a[ina.size() - i] = ina[i] - '0';
for (int i = inb.size() - 1; i >= 0; i--) b[inb.size() - i] = inb[i] - '0';
//从下标1开始存 地位在前
int max;
ina.size() > inb.size() ? max = ina.size() : max = inb.size();
for (int i = 1; i <= max;i++)
{
sum[i] += (a[i] + b[i]);
if (sum[i] >= 10)
{
sum[i + 1]++;
sum[i] %= 10;
}
}
int p = 509;
while (sum[--p] == 0&&p>1); //去掉前置0但是留一个避免全是0的情况
while (p)
{
printf("%d", sum[p--]);
}
return 0;
}
################################分割##################################
A*B Problem
题目背景
高精度乘法模板题。
题目描述
给出两个非负整数,求它们的乘积。
输入格式
输入共两行,每行一个非负整数。
输出格式
输出一个非负整数表示乘积。
样例 #1
样例输入 #1
1
2
样例输出 #1
2
提示
每个非负整数不超过 1 0 2000 10^{2000} 102000。
#include <iostream>
using namespace std;
//思路就是将人类的乘法思维用代码实现
int a[2010], b[2010], sum[4010];
int main()
{
string ina, inb;
cin >> ina >> inb;
for (int i = ina.size() - 1; i >= 0; i--) a[ina.size() - i] = ina[i] - '0';
for (int i = inb.size() - 1; i >= 0; i--) b[inb.size() - i] = inb[i] - '0';
//从下标1开始存 地位在前
for (int i = 1; i <= ina.size(); i++)
{
for (int j = 1; j <= inb.size(); j++)
{
sum[i + j - 1] += b[j] * a[i];
if (sum[i + j-1]>= 10) sum[i + j] += sum[i + j - 1] / 10;
sum[i + j - 1] %= 10;
}
}
int p = 4010;
while (sum[--p] == 0 && p > 1); //去掉前置0但是留一个避免全是0的情况
while (p)
{
printf("%d", sum[p--]);
}
return 0;
}
################################分割##################################
[NOIP1998 普及组] 阶乘之和
题目描述
用高精度计算出 S = 1 ! + 2 ! + 3 ! + ⋯ + n ! S = 1! + 2! + 3! + \cdots + n! S=1!+2!+3!+⋯+n!( n ≤ 50 n \le 50 n≤50)。
其中 !
表示阶乘,定义为
n
!
=
n
×
(
n
−
1
)
×
(
n
−
2
)
×
⋯
×
1
n!=n\times (n-1)\times (n-2)\times \cdots \times 1
n!=n×(n−1)×(n−2)×⋯×1。例如,
5
!
=
5
×
4
×
3
×
2
×
1
=
120
5! = 5 \times 4 \times 3 \times 2 \times 1=120
5!=5×4×3×2×1=120。
输入格式
一个正整数 n n n。
输出格式
一个正整数 S S S,表示计算结果。
样例 #1
样例输入 #1
3
样例输出 #1
9
提示
【数据范围】
对于 100 % 100 \% 100% 的数据, 1 ≤ n ≤ 50 1 \le n \le 50 1≤n≤50。
【其他说明】
注,《深入浅出基础篇》中使用本题作为例题,但是其数据范围只有 n ≤ 20 n \le 20 n≤20,使用书中的代码无法通过本题。
如果希望通过本题,请继续学习第八章高精度的知识。
NOIP1998 普及组 第二题
#include <iostream>
using namespace std;
//还算不算高精度乘法,高精度与低精度的乘法,
//以及高精度加法的结合
int jc[110], sum[110];
int main()
{
int n;
cin >> n;
jc[1] = 1;
int max = 2;
for (int i = 1; i <= n; i++)
{
for (int j = 1; j < max; j++) jc[j] *= i;
for (int j = 1; j < max; j++)
{
jc[j + 1] += jc[j] / 10;
jc[j] %= 10;
} //计算每一次阶乘后的值
while (jc[max] != 0) max++;
for (int j = 1; j < max; j++)
{
sum[j] += jc[j];
sum[j + 1] += sum[j] / 10;
sum[j] %= 10;
} //每一次阶乘后的和
while (sum[max] != 0) max++;
}
while (sum[max] == 0 && max > 1) max--;
while (max) printf("%d", sum[max--]);
return 0;
}
################################分割##################################
[1007] 魔法少女小Scarlet
题目描述
Scarlet 最近学会了一个数组魔法,她会在 n × n n\times n n×n 二维数组上将一个奇数阶方阵按照顺时针或者逆时针旋转 9 0 ∘ 90^\circ 90∘。
首先,Scarlet 会把 1 1 1 到 n 2 n^2 n2 的正整数按照从左往右,从上至下的顺序填入初始的二维数组中,然后她会施放一些简易的魔法。
Scarlet 既不会什么分块特技,也不会什么 Splay 套 Splay,她现在提供给你她的魔法执行顺序,想让你来告诉她魔法按次执行完毕后的二维数组。
输入格式
第一行两个整数 n , m n,m n,m,表示方阵大小和魔法施放次数。
接下来 m m m 行,每行 4 4 4 个整数 x , y , r , z x,y,r,z x,y,r,z,表示在这次魔法中,Scarlet 会把以第 x x x 行第 y y y 列为中心的 2 r + 1 2r+1 2r+1 阶矩阵按照某种时针方向旋转,其中 z = 0 z=0 z=0 表示顺时针, z = 1 z=1 z=1 表示逆时针。
输出格式
输出 n n n 行,每行 n n n 个用空格隔开的数,表示最终所得的矩阵
样例 #1
样例输入 #1
5 4
2 2 1 0
3 3 1 1
4 4 1 0
3 3 2 1
样例输出 #1
5 10 3 18 15
4 19 8 17 20
1 14 23 24 25
6 9 2 7 22
11 12 13 16 21
提示
对于50%的数据,满足 r = 1 r=1 r=1
对于100%的数据 1 ≤ n , m ≤ 500 1\leq n,m\leq500 1≤n,m≤500,满足 1 ≤ x − r ≤ x + r ≤ n , 1 ≤ y − r ≤ y + r ≤ n 1\leq x-r\leq x+r\leq n,1\leq y-r\leq y+r\leq n 1≤x−r≤x+r≤n,1≤y−r≤y+r≤n。
#include <iostream>
using namespace std;
//思路
//旋转思路如图
int d[510][510];
int main()
{
int n, m;
cin >> n >> m;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++) d[i][j] = (i-1)*n + j; //输入
while (m--)
{
int x, y, r, z;
cin >> x >> y >> r >> z;
if (z == 0)
{
for(int j = r;j>0;j--)
{
for (int i = 0; i < 2 * j; i++) //每一圈
{
swap(d[x - j][y - j + i], d[x - j + i][y + j]);
swap(d[x - j][y - j + i], d[x + j][y + j - i]);
swap(d[x - j][y - j + i], d[x + j - i][y - j]);
}
}
}
else
{
for (int j = r; j > 0; j--)
{
for (int i = 0; i < 2 * j; i++) //每一圈
{
swap(d[x - j + i][y - j], d[x + j][y - j + i]);
swap(d[x - j + i][y - j], d[x + j - i][y + j]);
swap(d[x - j + i][y - j], d[x - j][y + j - i]);
}
}
}
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
cout << d[i][j] << ' ';
cout << endl;
}
return 0;
}
旋转思路:从最外围开始,做交换操作,结合代码,着重考虑行列即可。(红点是中心)以顺时针旋转为例
################################分割##################################
[NOIP2014 提高组] 生活大爆炸版石头剪刀布
题目背景
NOIP2014 提高组 D1T1
题目描述
石头剪刀布是常见的猜拳游戏:石头胜剪刀,剪刀胜布,布胜石头。如果两个人出拳一样,则不分胜负。在《生活大爆炸》第二季第 8 集中出现了一种石头剪刀布的升级版游戏。
升级版游戏在传统的石头剪刀布游戏的基础上,增加了两个新手势:
斯波克:《星际迷航》主角之一。
蜥蜴人:《星际迷航》中的反面角色。
这五种手势的胜负关系如表一所示,表中列出的是甲对乙的游戏结果。
现在,小 A 和小 B 尝试玩这种升级版的猜拳游戏。已知他们的出拳都是有周期性规律的,但周期长度不一定相等。例如:如果小 A 以 石头-布-石头-剪刀-蜥蜴人-斯波克
长度为
6
6
6 的周期出拳,那么他的出拳序列就是 石头-布-石头-剪刀-蜥蜴人-斯波克-石头-布-石头-剪刀-蜥蜴人-斯波克-...
,而如果小 B 以 剪刀-石头-布-斯波克-蜥蜴人
长度为
5
5
5 的周期出拳,那么他出拳的序列就是 剪刀-石头-布-斯波克-蜥蜴人-剪刀-石头-布-斯波克-蜥蜴人-...
。
已知小 A 和小 B 一共进行 N N N 次猜拳。每一次赢的人得 1 1 1 分,输的得 0 0 0 分;平局两人都得 0 0 0 分。现请你统计 N N N 次猜拳结束之后两人的得分。
输入格式
第一行包含三个整数: N , N A , N B N,N_A,N_B N,NA,NB,分别表示共进行 N N N 次猜拳、小 A 出拳的周期长度,小 B 出拳的周期长度。数与数之间以一个空格分隔。
第二行包含
N
A
N_A
NA 个整数,表示小 A 出拳的规律,第三行包含
N
B
N_B
NB 个整数,表示小 B 出拳的规律。其中,
0
0
0 表示 剪刀
,
1
1
1 表示 石头
,
2
2
2 表示 布
,
3
3
3 表示 蜥蜴人
,
4
4
4 表示 斯波克
。数与数之间以一个空格分隔。
输出格式
输出一行,包含两个整数,以一个空格分隔,分别表示小 A、小 B 的得分。
样例 #1
样例输入 #1
10 5 6
0 1 2 3 4
0 3 4 2 1 0
样例输出 #1
6 2
样例 #2
样例输入 #2
9 5 5
0 1 2 3 4
1 0 3 2 4
样例输出 #2
4 4
提示
对于 100 % 100\% 100% 的数据, 0 < N ≤ 200 , 0 < N A ≤ 200 , 0 < N B ≤ 200 0 < N \leq 200, 0 < N_A \leq 200, 0 < N_B \leq 200 0<N≤200,0<NA≤200,0<NB≤200 。
#include <iostream>
using namespace std;
//补全表格后就了然了
int n, a[210], b[210];
pair<int, int> p[5];
void init()
{
p[0].first = 2; p[0].second = 3;
p[1].first = 0; p[1].second = 3;
p[2].first = 1; p[2].second = 4;
p[3].first = 2; p[3].second = 4;
p[4].first = 0; p[4].second = 1;
}
int main()
{
init();
int na, nb;
cin >> n >> na >> nb;
int pa = 0 , pb = 0;
int va = 0, vb = 0;
for (int i = 0; i < na; i++) cin >> a[i];
for (int i = 0; i < nb; i++) cin >> b[i];
while (n--)
{
if (a[pa] != b[pb])
{
if (b[pb] == p[a[pa]].first || b[pb] == p[a[pa]].second) va++;
else vb++;
}
pa++; pb++;
pa %= na;
pb %= nb;
}
cout << va << ' ' << vb << endl;
return 0;
}
################################分割##################################
[USACO2.4] 两只塔姆沃斯牛 The Tamworth Two
题目描述
两只牛逃跑到了森林里。Farmer John 开始用他的专家技术追捕这两头牛。你的任务是模拟他们的行为(牛和 John)。
追击在 10 × 10 10 \times 10 10×10 的平面网格内进行。一个格子可以是:一个障碍物,两头牛(它们总在一起),或者 Farmer John。两头牛和 Farmer John 可以在同一个格子内(当他们相遇时),但是他们都不能进入有障碍的格子。
一个格子可以是:
.
空地;*
障碍物;C
两头牛;F
Farmer John。
这里有一个地图的例子:
*...*.....
......*...
...*...*..
..........
...*.F....
*.....*...
...*......
..C......*
...*.*....
.*.*......
牛在地图里以固定的方式游荡。每分钟,它们可以向前移动或是转弯。如果前方无障碍(地图边沿也是障碍),它们会按照原来的方向前进一步。否则它们会用这一分钟顺时针转 90 度。 同时,它们不会离开地图。
Farmer John 深知牛的移动方法,他也这么移动。
每次(每分钟)Farmer John 和两头牛的移动是同时的。如果他们在移动的时候穿过对方,但是没有在同一格相遇,我们不认为他们相遇了。当他们在某分钟末在某格子相遇,那么追捕结束。
读入十行表示地图。每行都只包含 10 个字符,表示的含义和上面所说的相同。保证地图中只有一个 F
和一个 C
。F
和 C
一开始不会处于同一个格子中。
计算 Farmer John 需要多少分钟来抓住他的牛,假设牛和 Farmer John 一开始的行动方向都是正北(即上)。 如果 John 和牛永远不会相遇,输出 0。
输入格式
输入共十行,每行 10 个字符,表示如上文描述的地图。
输出格式
输出一个数字,表示 John 需要多少时间才能抓住牛们。如果 John 无法抓住牛,则输出 0。
样例 #1
样例输入 #1
*...*.....
......*...
...*...*..
..........
...*.F....
*.....*...
...*......
..C......*
...*.*....
.*.*......
样例输出 #1
49
提示
翻译来自NOCOW
USACO 2.4
#include <iostream>
#include <vector>
using namespace std;
//这个题就难在判断结束条件上,
//刚开始想的是当再次以同样的方向站在同样的点上时
//就意味着永远碰不见,但是这种方法忽略了大圈小圈有交点的情况,
//然后就是修改了判断条件,能ac但是不合逻辑,bug依然存在。
//代码存在很多值得优化的地方, 但是现在不想修,因为今天是周六OwO
char d[4] = { 'u','r','d','l' };
char dirf='u',dirc= 'u'; //0123上 右 下 左
int n = 0;
string f[10][10], c[10][10];
vector<string> v;
int timec = 0, timef = 0;
void move(int &x,int &y,char &dir,char an)
{
//向上走
if (dir == 'u')
{
if (x == 0 || v[x - 1][y] == '*') dir = 'r'; //拐弯情况
else
{
v[x][y] = '.'; //原来的地方变草坪
x--; //走一步
}
}
//向右走
else if (dir == 'r')
{
if (y == n-1 || v[x][y+1] == '*') dir = 'd'; //拐弯情况
else
{
v[x][y] = '.'; //原来的地方变草坪
y++; //走一步
}
}
//向下走
else if (dir == 'd')
{
if (x == n - 1 || v[x+1][y] == '*') dir = 'l'; //拐弯情况
else
{
v[x][y] = '.'; //原来的地方变草坪
x++; //走一步
}
}
//向左走
else if (dir == 'l')
{
if (y == 0 || v[x][y - 1] == '*') dir = 'u'; //拐弯情况
else
{
v[x][y] = '.'; //原来的地方变草坪
y--; //走一步
}
}
v[x][y] = an;
}
int main()
{
int fx=0, fy=-1, cx=0, cy=-1;
string in;
while(cin>>in)
{
if (fy == -1)
{
fy = in.find('F');
fx = n;
}
if (cy == -1)
{
cy = in.find('C');
cx = n;
}
v.push_back(in);
n++;
} //都是从下标0开始的
int flagf = 0, flagc = 0, step=0;
while (1)
{
if (fx == cx && fy == cy)
{
cout << step << endl;
return 0;
}
if (f[fx][fy].find(dirf) != -1)
{
flagf++;
}
if (c[cx][cy].find(dirc) != -1)
{
flagc++;
}
if (flagf>=400 && flagc>=400)//其实是不严谨的,但是能过题目。
{
cout << 0 << endl;
return 0;
}
f[fx][fy] += dirf; c[cx][cy] += dirc;
move(fx, fy, dirf, 'F');
move(cx, cy, dirc, 'C');
step++;
}
return 0;
}
################################分割##################################
[NOIP2009 普及组] 多项式输出
题目描述
一元 n n n 次多项式可用如下的表达式表示:
f ( x ) = a n x n + a n − 1 x n − 1 + ⋯ + a 1 x + a 0 , a n ≠ 0 f(x)=a_nx^n+a_{n-1}x^{n-1}+\cdots +a_1x+a_0,a_n\ne 0 f(x)=anxn+an−1xn−1+⋯+a1x+a0,an=0
其中, a i x i a_ix^i aixi 称为 i i i 次项, a i a_i ai 称为 i i i 次项的系数。给出一个一元多项式各项的次数和系数,请按照如下规定的格式要求输出该多项式:
-
多项式中自变量为 x x x,从左到右按照次数递减顺序给出多项式。
-
多项式中只包含系数不为 0 0 0 的项。
-
如果多项式 n n n 次项系数为正,则多项式开头不出
+
号,如果多项式 n n n 次项系数为负,则多项式以-
号开头。 -
对于不是最高次的项,以
+
号或者-
号连接此项与前一项,分别表示此项系数为正或者系数为负。紧跟一个正整数,表示此项系数的绝对值(如果一个高于 0 0 0 次的项,其系数的绝对值为 1 1 1,则无需输出 1 1 1)。如果 x x x 的指数大于 1 1 1,则接下来紧跟的指数部分的形式为“ x b x^b xb”,其中 b b b 为 x x x 的指数;如果 x x x 的指数为 1 1 1,则接下来紧跟的指数部分形式为 x x x;如果 x x x 的指数为 0 0 0,则仅需输出系数即可。 -
多项式中,多项式的开头、结尾不含多余的空格。
输入格式
输入共有 2 2 2 行
第一行 1 1 1 个整数, n n n,表示一元多项式的次数。
第二行有 n + 1 n+1 n+1 个整数,其中第 i i i 个整数表示第 n − i + 1 n-i+1 n−i+1 次项的系数,每两个整数之间用空格隔开。
输出格式
输出共 1 1 1 行,按题目所述格式输出多项式。
样例 #1
样例输入 #1
5
100 -1 1 -3 0 10
样例输出 #1
100x^5-x^4+x^3-3x^2+10
样例 #2
样例输入 #2
3
-50 0 0 1
样例输出 #2
-50x^3+1
提示
NOIP 2009 普及组 第一题
对于100%数据, 0 ≤ n ≤ 100 0 \le n \le 100 0≤n≤100,$-100 \le 系数 系数 系数 \le 100$
upd 2022.8.1 \text{upd 2022.8.1} upd 2022.8.1:新增加一组 Hack 数据。
#include <iostream>
using namespace std;
//坑最多的一集
//考虑系数是1的情况
//考虑系数为0的情况
//考虑次数为1的情况
//考虑次数为0的情况
int coeffice[110];
int main()
{
int n;
cin >> n;
for (int i = n; i >= 0; i--) cin >> coeffice[i];
int i = n;
while (i>=0&&coeffice[i--] == 0); //去掉前置0 好像是没必要,自己尝试删掉也行
i++;
if (coeffice[i] < 0) cout << '-'; //因为后面每一项的符号都是在上一项中输出的。
//你前面是0且你是正数,总不能只输出个+
while (i)
{
if (coeffice[i] == 0) {}
else if(i>1)
{
if (abs(coeffice[i]) == 1) cout << "x^" << i; //次数问题
else cout << abs(coeffice[i]) << "x^" << i;
}
else
{
if (abs(coeffice[i]) == 1) cout << "x";
else cout << abs(coeffice[i]) << "x";
}
if (coeffice[i - 1] > 0) cout << '+';
else if (coeffice[i - 1] < 0) cout << '-';//单独输出符号是因为-1的问题
i--;
}
if(abs(coeffice[0])||n==0)
cout << abs(coeffice[0]);
return 0;
}
################################分割##################################
[NOIP2007 提高组] 字符串的展开
题目描述
在初赛普及组的“阅读程序写结果”的问题中,我们曾给出一个字符串展开的例子:如果在输入的字符串中,含有类似于 d-h
或者 4-8
的字串,我们就把它当作一种简写,输出时,用连续递增的字母或数字串替代其中的减号,即,将上面两个子串分别输出为 defgh
和 45678
。在本题中,我们通过增加一些参数的设置,使字符串的展开更为灵活。具体约定如下:
(1) 遇到下面的情况需要做字符串的展开:在输入的字符串中,出现了减号 -
,减号两侧同为小写字母或同为数字,且按照 ASCII
码的顺序,减号右边的字符严格大于左边的字符。
(2) 参数
p
1
p_1
p1:展开方式。
p
1
=
1
p_1=1
p1=1 时,对于字母子串,填充小写字母;
p
1
=
2
p_1=2
p1=2 时,对于字母子串,填充大写字母。这两种情况下数字子串的填充方式相同。
p
1
=
3
p_1=3
p1=3 时,不论是字母子串还是数字字串,都用与要填充的字母个数相同的星号 *
来填充。
(3) 参数
p
2
p_2
p2:填充字符的重复个数。
p
2
=
k
p_2=k
p2=k 表示同一个字符要连续填充
k
k
k 个。例如,当
p
2
=
3
p_2=3
p2=3 时,子串d-h
应扩展为 deeefffgggh
。减号两边的字符不变。
(4) 参数
p
3
p_3
p3:是否改为逆序:
p
3
=
1
p_3=1
p3=1 表示维持原来顺序,
p
3
=
2
p_3=2
p3=2 表示采用逆序输出,注意这时候仍然不包括减号两端的字符。例如当
p
1
=
1
p_1=1
p1=1、
p
2
=
2
p_2=2
p2=2、
p
3
=
2
p_3=2
p3=2 时,子串 d-h
应扩展为 dggffeeh
。
(5) 如果减号右边的字符恰好是左边字符的后继,只删除中间的减号,例如:d-e
应输出为 de
,3-4
应输出为 34
。如果减号右边的字符按照 ASCII
码的顺序小于或等于左边字符,输出时,要保留中间的减号,例如:d-d
应输出为 d-d
,3-1
应输出为 3-1
。
输入格式
共两行。
第 1 1 1 行为用空格隔开的 3 3 3 个正整数,依次表示参数 p 1 , p 2 , p 3 p_1,p_2,p_3 p1,p2,p3。
第
2
2
2 行为一行字符串,仅由数字、小写字母和减号 -
组成。行首和行末均无空格。
输出格式
共一行,为展开后的字符串。
样例 #1
样例输入 #1
1 2 1
abcs-w1234-9s-4zz
样例输出 #1
abcsttuuvvw1234556677889s-4zz
样例 #2
样例输入 #2
2 3 2
a-d-d
样例输出 #2
aCCCBBBd-d
提示
40 % 40\% 40% 的数据满足:字符串长度不超过 5 5 5。
100 % 100\% 100% 的数据满足: 1 ≤ p 1 ≤ 3 , 1 ≤ p 2 ≤ 8 , 1 ≤ p 3 ≤ 2 1 \le p_1 \le 3,1 \le p_2 \le 8,1 \le p_3 \le 2 1≤p1≤3,1≤p2≤8,1≤p3≤2。字符串长度不超过 100 100 100。
NOIP 2007 提高第二题
#include <iostream>
#include <algorithm>
using namespace std;
//1:'-'代表缩写
//参数1:'1' 字母填小写,'2'大写,'3'星号
//参数2:连续填充几个
//参数3:2是 1否 逆序
//挨个遍历,检测到'-'的时候判断一下,如果是缩写的话,构建字符串后替代'-'
string in;
char base;
int p1, p2, p3;
int main()
{
cin >> p1 >> p2 >> p3;
cin >> in;
int flag = p1 / 2; //大小写标志
for (int i = 0; i < in.size(); i++)
{
if (in[i] == '-')
{
//直接输出的情况 避免越界
if (i == 0 || i == in.size() - 1 || in[i - 1] >= in[i + 1]) continue;
//处理数字
if ((in[i - 1] >= '0' && in[i - 1] <= '9')&& (in[i + 1] >= '0' && in[i + 1] <= '9'))
{
base = in[i - 1] + 1;
string temp;
while (base < in[i + 1]) //避免两个相连情况
{
if (p1 == 3) //加星号的情况
for (int i = 1; i <= p2; i++) temp += '*';
else
for (int i = 1; i <= p2; i++) temp += base;
base++;
}
if (p3 == 2) reverse(temp.begin(), temp.end());//逆序了
in.replace(i, 1, temp);
}
//处理小写字母
else if((in[i - 1] >= 'a' && in[i - 1] <= 'z') && (in[i + 1] >= 'a' && in[i + 1] <= 'z'))
{
base = in[i - 1] + 1;
string temp;
while (base < in[i + 1]) //避免两个相连情况
{
if (p1 == 3) //加星号的情况
for (int i = 1; i <= p2; i++) temp += '*';
else
for (int i = 1; i <= p2; i++) temp += (base-flag*32);
base++;
}
if (p3 == 2) reverse(temp.begin(), temp.end());//逆序了
in.replace(i, 1, temp);
}
}
}
cout << in << endl;
return 0;
}
################################分割##################################
P1065作业调度问题还没有写出来 非常抱歉
################################分割##################################
帮贡排序
题目背景
在 absi2011 的帮派里,死号偏多。现在 absi2011 和帮主等人联合决定,要清除一些死号,加进一些新号,同时还要鼓励帮贡多的人,对帮派进行一番休整。
题目描述
目前帮派内共最多有一位帮主,两位副帮主,两位护法,四位长老,七位堂主,二十五名精英,帮众若干。
现在 absi2011 要对帮派内几乎所有人的职位全部调整一番。他发现这是个很难的事情。于是要求你帮他调整。
他给你每个人的以下数据:
他的名字(长度不会超过 30 30 30),他的原来职位,他的帮贡,他的等级。
他要给帮贡最多的护法的职位,其次长老,以此类推。
可是,乐斗的显示并不按帮贡排序而按职位和等级排序。
他要你求出最后乐斗显示的列表(在他调整过职位后):职位第一关键字,等级第二关键字。
注意:absi2011 无权调整帮主、副帮主的职位,包括他自己的(这不是废话么…)
他按原来的顺序给你(所以,等级相同的,原来靠前的现在也要靠前,因为经验高低的原因,但此处为了简单点省去经验。)
输入格式
第一行一个正整数 n n n,表示星月家园内帮友的人数。
下面 n n n 行每行两个字符串两个整数,表示每个人的名字、职位、帮贡、等级。
输出格式
一共输出 n n n 行,每行包括排序后乐斗显示的名字、职位、等级。
样例 #1
样例输入 #1
9
DrangonflyKang BangZhu 100000 66
RenZaiJiangHu FuBangZhu 80000 60
absi2011 FuBangZhu 90000 60
BingQiLingDeYanLei HuFa 89000 58
Lcey HuFa 30000 49
BangYou3 ZhangLao 1000 1
BangYou1 TangZhu 100 40
BangYou2 JingYing 40000 10
BangYou4 BangZhong 400 1
样例输出 #1
DrangonflyKang BangZhu 66
RenZaiJiangHu FuBangZhu 60
absi2011 FuBangZhu 60
BingQiLingDeYanLei HuFa 58
BangYou2 HuFa 10
Lcey ZhangLao 49
BangYou1 ZhangLao 40
BangYou3 ZhangLao 1
BangYou4 ZhangLao 1
提示
各种职位用汉语拼音代替。
如果职位剩 1 1 1 个,而有 2 2 2 个帮贡相同的人,则选择原来在前的现在当选此职位。
另:
帮派名号:星月家园
帮主尊号:Dragonfly Kang
帮派ID:2685023
帮派等级:4
帮派人数:101/110
帮派技能:
星月家园资料,欢迎各位豆油加入_
【数据范围】
对于 10 % 10\% 10% 的数据,保证 n = 3 n=3 n=3。
对于 40 % 40\% 40% 的数据,保证各个人的帮贡均为 0 0 0。
对于
100
%
100\%
100% 的数据,保证
3
≤
n
≤
110
3\leq n\leq 110
3≤n≤110,各个名字长度
≤
30
\leq30
≤30,
0
≤
0\leq
0≤ 各个人的帮贡
≤
1000000000
\leq1000000000
≤1000000000,
1
≤
1\leq
1≤ 各个人等级
≤
150
\leq 150
≤150。
保证职位必定为 BangZhu \texttt{BangZhu} BangZhu, FuBangZhu \texttt{FuBangZhu} FuBangZhu, HuFa \texttt{HuFa} HuFa, ZhangLao \texttt{ZhangLao} ZhangLao, TangZhu \texttt{TangZhu} TangZhu, JingYing \texttt{JingYing} JingYing, BangZhong \texttt{BangZhong} BangZhong 之中的一个
保证有一名帮主,保证有两名副帮主,保证有一名副帮主叫 absi2011
不保证一开始帮派里所有职位都是满人的,但排序后分配职务请先分配高级职位。例如原来设一名护法现在设两名。
保证名字不重复。
【题目来源】
fight.pet.qq.com
absi2011 授权题目
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
string table[5] = { "HuFa","ZhangLao","TangZhu","JingYing","BangZhong" };
int wp = 0;
class people
{
public:
people(string n, string w, int g, int r,int z)
{
name = n, work = w, gx = g, rank = r, zz = z;
}
void display()
{
cout << this->name << ' ' << this->work << ' ' << this->rank << endl;
}
string name, work;
int gx, rank, zz;
};
bool cmp(people p1, people p2)
{
if (p1.gx == p2.gx) //贡献相同时以插入顺序为依据
return p1.zz < p2.zz;
else
return p1.gx > p2.gx;
}
bool cmp2(people p1, people p2)
{
if (p1.rank == p2.rank)
return p1.zz < p2.zz;
else
return p1.rank > p2.rank;
}
int min(int x, int y)
{
if (x > y)return y;
return x;
}
int main()
{
int n;
cin >> n;
vector<people> v1;
int z = 0;
while(n--)
{
string name, work;
int gx, rank;
cin >> name >> work >> gx >> rank;
people p(name, work, gx, rank,z++);
v1.push_back(p);
}
vector<people> v2 = v1;
int bp = 1;
for (auto i : v1)
{
if (i.work == "BangZhu") v2[0] = i;
if (i.work == "FuBangZhu") v2[bp++] = i;
}
sort(v1.begin(), v1.end(), cmp); //按照贡献排序
int cp = 3;
for (int i = 0; i < v1.size(); i++)
{
if (v1[i].work != "BangZhu" && v1[i].work != "FuBangZhu")
{
v2[cp] = v1[i];
v2[cp++].work = table[wp];
}
if (cp > 4) wp = 1;
if (cp > 8) wp = 2;
if (cp > 15)wp = 3;
if (cp > 40)wp = 4;
}
int add = 3;
do {
sort(v2.begin()+1, v2.begin()+min(3, v2.size()), cmp2);
if (add >= v2.size()) break;
add += 2; //5
sort(v2.begin()+3, v2.begin() + min(5, v2.size()), cmp2);
if (add >= v2.size()) break;
add += 4;//9
sort(v2.begin()+5, v2.begin() + min(9, v2.size()), cmp2);
if (add >= v2.size()) break;
add += 7;//16
sort(v2.begin()+9, v2.begin() + min(16, v2.size()), cmp2);
if (add >= v2.size()) break;
add += 25;//41
sort(v2.begin() + 16, v2.begin() + min(41, v2.size()), cmp2);
if (add >= v2.size()) break;
sort(v2.begin() + 41,v2.end(), cmp2);
} while (0);
for (auto i : v2)
{
i.display();
}
return 0;
}
################################分割##################################
阶乘数码
题目描述
求 n ! n! n! 中某个数码出现的次数。
输入格式
第一行为 t ( t ≤ 10 ) t(t \leq 10) t(t≤10),表示数据组数。接下来 t t t 行,每行一个正整数 n ( n ≤ 1000 ) n(n \leq 1000) n(n≤1000) 和数码 a a a。
输出格式
对于每组数据,输出一个整数,表示 n ! n! n! 中 a a a 出现的次数。
样例 #1
样例输入 #1
2
5 2
7 0
样例输出 #1
1
2
#include <iostream>
using namespace std;
//高精度,构建数据范围内所有的阶乘数组
int jc[1010][2610]; //1000的阶乘大约有502位
void init()
{
jc[1][0] = 1;
jc[1][1] = 1;
int max = 1;
for (int i = 2; i <= 1000; i++)
{
for (int j = 1; j <= max; j++)
{
jc[i][j] =jc[i-1][j]*i;
}
int k = 1;
while (k <= max)
{
if (jc[i][k] >= 10)
{
jc[i][k + 1] += jc[i][k] / 10;
jc[i][k] %= 10;
}
if (jc[i][max + 1]!=0) max++;
k++;
}
jc[i][0] = max;
}
}
int main()
{
init();
int work;
cin >> work;
while (work--)
{
int num, flag,cont=0;
cin >> num >> flag;
for (int i = 1; i <= jc[num][0]; i++)
if (jc[num][i] == flag) cont++;
cout << cont << endl;
}
return 0;
}
################################分割##################################
[NOIP2003 普及组] 麦森数
题目描述
形如 2 P − 1 2^{P}-1 2P−1 的素数称为麦森数,这时 P P P 一定也是个素数。但反过来不一定,即如果 P P P 是个素数, 2 P − 1 2^{P}-1 2P−1 不一定也是素数。到 1998 年底,人们已找到了 37 个麦森数。最大的一个是 P = 3021377 P=3021377 P=3021377,它有 909526 位。麦森数有许多重要应用,它与完全数密切相关。
任务:输入 P ( 1000 < P < 3100000 ) P(1000<P<3100000) P(1000<P<3100000),计算 2 P − 1 2^{P}-1 2P−1 的位数和最后 500 500 500 位数字(用十进制高精度数表示)
输入格式
文件中只包含一个整数 P ( 1000 < P < 3100000 ) P(1000<P<3100000) P(1000<P<3100000)
输出格式
第一行:十进制高精度数 2 P − 1 2^{P}-1 2P−1 的位数。
第 2 ∼ 11 2\sim 11 2∼11 行:十进制高精度数 2 P − 1 2^{P}-1 2P−1 的最后 500 500 500 位数字。(每行输出 50 50 50 位,共输出 10 10 10 行,不足 500 500 500 位时高位补 0 0 0)
不必验证 2 P − 1 2^{P}-1 2P−1 与 P P P 是否为素数。
样例 #1
样例输入 #1
1279
样例输出 #1
386
00000000000000000000000000000000000000000000000000
00000000000000000000000000000000000000000000000000
00000000000000104079321946643990819252403273640855
38615262247266704805319112350403608059673360298012
23944173232418484242161395428100779138356624832346
49081399066056773207629241295093892203457731833496
61583550472959420547689811211693677147548478866962
50138443826029173234888531116082853841658502825560
46662248318909188018470682222031405210266984354887
32958028878050869736186900714720710555703168729087
提示
【题目来源】
NOIP 2003 普及组第四题
#include <iostream>
#include <math.h>
#include <cmath>
using namespace std;
unsigned long long fin[510];
//如果每次乘2会超时,所以一次性乘多个2的次幂
//暂时未掌握快速幂,这里不使用,以后再来重写
int main()
{
int n;
cin >> n;
fin[1] = 1;
int max = 1;
int div = n / 60, rem = n % 60; //最大是60次方 61次方乘9会超范围
unsigned long long temp1 = pow(2, 60), temp2 = pow(2, rem);
for (int i = 0; i <= div; i++)
{
if (i==0)
{
for (int j = 1; j <= 500; j++)
{
fin[j] *= temp2;
}
}
else
{
for (int j = 1; j <= 500; j++)
{
fin[j] *= temp1;
}
}
for (int k = 1; k <= 500; k++)
{
if (fin[k] >= 10)
{
fin[k + 1] += fin[k] / 10;
fin[k] %= 10;
}
}
}
fin[1]--;//减一
for (int i = 1; i <= 500; i++)
{
if (fin[i] < 0)
{
fin[i] += 10;
fin[i + 1] -= 1;
}
}
int p = 0;
cout<< ceil(log10(2)*n)<<endl; //计算位数的公式
for (int i = 500; i > 0; i--) //输出
{
cout << fin[i];
p++;
if (p == 50)
{
cout << endl;
p = 0;
}
}
return 0;
}