一.平方末尾

题目描述

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

能够表示为某个整数的平方的数字称为“平方数”

虽然无法立即说出某个数是平方数,但经常可以断定某个数不是平方数。 因为平方数的末位只可能是:[0,1,4,5,6,9] 这 66 个数字中的某个。 所以,4325435332 必然不是平方数。

如果给你一个 2 位或 2 位以上的数字,你能根据末位的两位来断定它不是平方数吗?

请计算一下,一个 2 位以上的平方数的最后两位有多少种可能性?

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 128M

思路:我们只需要两位数生成平方数的最后两位的所有情况,再根据题意进行判断即可。

当超过两位数的时候,由于高于两位数的数位并不会对最后两位的值产生影响,因此只需要枚举0-99即可。(当然由于10*10 = 100,100%100=0,因此本程序已经在10的时候包含了00)

例如:123 * 456,当1与456中的数位做乘法的时候,就算是对于个位6,乘法后的数位会在百位上,并不会影响到个位和十位。

#include <bits/stdc++.h>
using namespace std;
int main()
{int i, j;set<int> number;for(i = 10; i < 100; ++ i){j = i * i;number.insert(j % 100);}cout << number.size();return 0;
}

二.质数拆分

题目描述

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

将 2019 拆分为若干个两两不同的质数之和,一共有多少种不同的方法?

注意交换顺序视为同一种方法,例如 2 + 2017 = 2019 与 2017 + 2 = 2019 视为同一种方法。

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 128M

思路:注意本题说的两两不同并不是说只能由两个数组成。

dp[i]定义为组成i的方案数,初始化dp[0]=1,这是因为2019不是质数,因此需要组合出2019,至少需要两个质数。

本题就是一个变种的0-1背包问题,dp[i]记录的是组合方案数。

#include <iostream>
#include <cstring>
using namespace std;bool notPrime[2020];
int primes[2020], cnt;
const int n = 2019;void euler(int num)
{int i, j;for(i = 2; i <= num; ++ i){if(!notPrime[i]){primes[cnt ++] = i;}for(j = 0; j < cnt && primes[j] * i <= num; ++ j){notPrime[primes[j] * i] = true;if(i % primes[j] == 0){break;}}}
}int main()
{long long dp[2020], i, j;memset(dp, 0, sizeof(dp));dp[0] = 1;euler(n);for(i = 0; i < cnt; ++ i){for(j = n; j >= primes[i]; -- j){dp[j] += dp[j - primes[i]];}}cout << dp[n];return 0;
}

三.拼接

题目描述

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

小明要把一根木头切成两段,然后拼接成一个直角。

如下图所示,他把中间部分分成了 n×n 的小正方形,他标记了每个小正方形属于左边还是右边。然后沿两边的分界线将木头切断,将右边旋转向上后拼 接在一起。

要求每个小正方形都正好属于左边或右边,而且同一边的必须是连通的。在拼接时,拼接的部位必须保持在原来大正方形里面。

请问,对于 7×7 的小正方形,有多少种合法的划分小正方形的方式。

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 128M

思路:可以发现,只需要切分前后,两个部分的方块都是关于反对角线对称的即可。拼接的方案就是把右边部分向上翻折即可。因此本题问的就是有什么方法保证切割后左右两部分要么没有,要么是关于反对角线对称的。实际上我们可以以反对角线经过的格点为起点,遍历上面的部分,注意不要越过反对角线,当遍历到边界的时候,对称到下面部分,就可以将图形分开为两个满足条件的部分。

#include <iostream>
using namespace std;
const int n = 7;
bool visited[n + 5][n + 5];void DFS(int x, int y, int& ans)
{if(!x || x == n || !y || y == n){++ ans;return;}//向上走 不可能越过反对角线if(x > 0 && !visited[x - 1][y]){visited[x - 1][y] = true;DFS(x - 1, y, ans);visited[x - 1][y] = false;}//向左走 不可能越过反对角线if(y > 0 && !visited[x][y - 1]){visited[x][y - 1] = true;DFS(x, y - 1, ans);visited[x][y- 1] = false;}//向下走 且 不越过反对角线if(x < n && x + 1 + y < n && !visited[x + 1][y]){visited[x + 1][y] = true;DFS(x + 1, y, ans);visited[x + 1][y] = false;}//向右走 且 不越过反对角线if(y < n && x + y + 1 < n && !visited[x][y + 1]){visited[x][y + 1] = true;DFS(x, y + 1, ans);visited[x][y + 1] = false;}
}int main()
{int sx = n, sy = 0, ans;while(sx >= 0 && sy <= n){visited[sx][sy] = true;DFS(sx, sy, ans);visited[sx][sy] = false;-- sx;++ sy;}cout << ans;return 0;
}

四.求值

题目描述

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

学习了约数后,小明对于约数很好奇,他发现,给定一个正整数 t,总是可以找到含有 t 个约数的整数。小明对于含有 t 个约数的最小数非常感兴趣,并把它定义为
例如 S1​ = 1, S2​ = 2, S3​ = 4, S4​ = 6,· · ·。 现在小明想知道,当 t = 100 时,St​是多少?即 S100​是多少?

思路:本题是填空题,直接暴力解就可以啦,暴力解结果再填空就行。

#include <iostream>
using namespace std;
typedef long long LL;int main()
{LL num, fac;int factor_num;for(num = 1; ; ++ num){factor_num = 0;for(fac = 1; fac * fac <= num; ++ fac){if(num % fac == 0){if(num == fac * fac){++ factor_num;}else{factor_num = factor_num + 2;}}}if(factor_num == 100){cout << num;break;}}
}

五.路径计数

题目描述

本题为填空题,只需要算出结果后,在代码中使用输出语句将所填结果输出即可。

从一个 5×5 的方格矩阵的左上角出发,沿着方格的边走,满足以下条件的路线有多少种?

  1. 总长度不超过 12;
  2. 最后回到左上角;
  3. 路线不自交;
  4. 不走出 5×5 的方格矩阵范围之外。 如下图所示ABC 是三种合法的路线。注意 B 和 C 由于方向不同,所以 视为不同的路线。

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 128M

思路:DFS,本题要求最后回到出发点,且路径长度<=12,对格点进行DFS即可。需要注意的是,我们只要要求路径长度>2,就可以防止路径出去就回来:

#include <iostream>
using namespace std;
const int n = 5;bool visited[n + 5][n + 5];
int ans, dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};bool check(int x, int y)
{return x >= 0 && x < n && y >= 0 && y < n;
}void DFS(int x, int y, int path_len)
{if(path_len > 12){return;}//最后回到了出发点0,0if(!x && !y && path_len > 2){++ ans;return;}for(int i = 0; i < 4; ++ i){int nx = dir[i][0] + x;int ny = dir[i][1] + y;if(check(nx, ny) && !visited[nx][ny]){visited[nx][ny] = true;DFS(nx, ny, path_len + 1);visited[nx][ny] = false;}}
}int main()
{DFS(0, 0, 0);cout << ans;return 0;
}

注:本题的标准答案排除了走到边界点(0,5)和(5,0)的情况,包括他们的正向和逆向,共4种。但实际上他们的路径长度都为12,是满足题意的,有争议。

六.最优包含

题目描述

我们称一个字符串 S 包含字符串 T 是指 T 是 S 的一个子序列,即可以从字符串 S 中抽出若干个字符,它们按原来的顺序组合成一个新的字符串与 T 完全一样。

给定两个字符串 S 和 T,请问最少修改 S 中的多少个字符,能使 S 包含 T ?

其中,1≤∣T∣≤∣S∣≤1000。

输入描述

输入两行,每行一个字符串。

第一行的字符串为 S,第二行的字符串为 T。

两个字符串均非空而且只包含大写英文字母。

输出描述

输出一个整数,表示答案。

输入输出样例

示例

输入

ABCDEABCD
XAABZ

输出

3

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M

思路:本题的题意就是要求最少修改S串中的字符,使得T是S的子序列。

我们定义dp[i][j]表示S[1~i]包含T[1~j]:

A.假如当前要考虑的是dp[i][j],那么如果S[i]=T[j],显然dp[i][j]=dp[i-1][j-1]。

B.否则,我们可以选择:dp[i][j]=min(dp[i-1][j-1]+1,dp[i-1][j])。

1.将S[i]改变为T[j],此时步数为dp[i-1][j-1]+1

2.让S[1~i-1]包含T[1~j],此时步数为dp[i-1][j]

值得注意的是:

1.dp[i][0]=0(0<=i<=n),因为空串是任意长度的串的子序列。

2.对于dp[i][j](i<j)是非法的,但是由于状态转移的时候,dp[i][j]=min(dp[i-1][j-1]+1,dp[i][j]=dp[i-1][j])是取min的,因此我们可以初始化为一个很大的数,利用取min的性质,就可以用大数表示非法状态,进而在取min的时候直接舍弃。

#include <iostream>
#include <string>
#include <cstring>
using namespace std;const int MaxN = 1005;int dp[MaxN][MaxN];
char S[MaxN] ,T[MaxN];int main()
{cin >> S + 1 >> T + 1;int i, j, n = strlen(S + 1), m = strlen(T + 1);  memset(dp, 0x3f3f, sizeof(dp));dp[0][0] = 0;for(i = 1; i <= n; ++ i){dp[i][0] = 0;for(j = 1; j <= m && j <= i; ++ j){if(S[i] == T[j]){dp[i][j] = dp[i - 1][j - 1];}else // 可以选择修改 S[i] = T[j],修改数量为dp[i - 1][j - 1] + 1; 也可以选择让S[1~i-1]包含T[1~j]{dp[i][j] = min(dp[i - 1][j - 1] + 1, dp[i - 1][j]);}}}cout << dp[n][m];return 0;
}

七.排列数

题目描述

在一个排列中,一个折点是指排列中的一个元素,它同时小于两边的元素,或者同时大于两边的元素。对于一个 1 ∼ n 的排列,如果可以将这个排列中包含 t 个折点,则它称为一个 t+1 单调序列。

例如,排列 (1,4,2,3) 是一个 3 单调序列,其中 4 和 2 都是折点。

给定 n 和 k,请问 1 ∼ n 的所有排列中有多少个 k 单调队列?

输入描述

输入一行包含两个整数 n,k (1≤k≤n≤500)。

输出描述

输出一个整数,表示答案。答案可能很大,你可需要输出满足条件的排列数量除以 123456 的余数即可。

输入输出样例

示例

输入

4 2

输出

12

运行限制

  • 最大运行时间:3s
  • 最大运行内存: 256M

思路:本题很直观的想法就是直接生成排列再按照条件进行统计。但是1~500的全排列还是比较容易超时的,当然我们也可以看k到底是接近1还是500,从而选择是从1~500开始用next_permutation还是从500~1开始用prev_permutation。但这都不是很好的想法,实际上思考排列,我们会发现,从1~n-1的排列得到1~n的排列只需要选择n放置在1~n-1的排列中的n个空位置中的某一个就可以了。大规模的排列是可以从小规模的排列推得的,我们可以尝试构想一下 从 1~i-1的排列,k-1个拐点 得到 1~i的排列,k个拐点的 迁移方式。

定义dp[i][k]表示1~i的排列中 拐点数量为k个的个数。

1.很显然,当i=1时,只有dp[i][0]=1是合法的,其余均非法。

2.当i=2时,只有dp[i][0]=2是合法的(从大到小与从小到大),其余均非法。(构成拐点至少3个点)

3.当i>2时,一切都玄乎了起来(雾):需要谨记我们考虑的i是当前考虑的数中最大的数

假设当前状态为dp[i][j]

A.i放置在当前已生成排列的左右两端

(1)拐点数量为偶数个  j为偶数

a.先波峰再波谷

由图很容易知道,这样做会在左端或者右端产生一个波谷(不可能是波峰是因为i是当前的最大值,而i在最边上,所以i不可能是拐点,而其他点都比他小,因此只能产生一个波谷)。

产生波谷:dp[i+1][j+1] = dp[i+1][j+1] + dp[i][j] / 2

不产生波谷:dp[i+1][j] = dp[i+1][j] + dp[i][j] / 2

注:dp[i][j]包含了先波峰后波谷与先波谷后波峰两种情况,且两种情况各占dp[i][j]的一半

b.先波谷后波峰

这种情况会在右端产生一个波谷,读者可以自行画图看看。

产生波谷:dp[i+1][j+1] = dp[i+1][j+1] + dp[i][j] / 2

不产生波谷:dp[i+1][j] = dp[i+1][j] + dp[i][j] / 2

综上,当j为偶数时

dp[i+1][j+1] = dp[i+1][j+1] + dp[i][j]

dp[i+1][j] = dp[i+1][j] + dp[i][j]

(2)拐点数量为奇数个  j为奇数

a.先波峰后波谷

由图很容易知道,这样做会在左端右端都会产生一个波谷

产生波谷:dp[i+1][j+1] = dp[i+1][j+1] + dp[i][j] / 2 * 2

dp[i][j] / 2:先波峰后波谷的情况占了dp[i][j]的一半

*2:这一半的情况中,左右两个端点都可以增加一个波谷

b.先波谷后波峰

读者可以画图看,我们这里直接证:由于是先波谷,因此有A[1]>A[2],此时我们让A[0]=i,就有A[0]>A[1]>A[2],并不会产生新的波峰或波谷。

同理,由于有奇数个拐点,因此A[i-2]与A[i-1]的关系可以推知是A[i-2]<A[i-1](不理解可以画图看),此时我们让A[i]=i,就有A[i-2]<A[i-1]<A[i],也不会产生新的波峰或波谷。

不产生波谷:dp[i+1][j] = dp[i+1][j] + dp[i][j]

综上,在奇数情况下,先峰后谷会产生两个波谷,先谷后峰不产生新的波峰或波谷,因此:

综上,当j为奇数时

产生波谷:dp[i+1][j+1] = dp[i+1][j+1] + dp[i][j]

不产生波谷:dp[i+1][j] = dp[i+1][j] + dp[i][j]

综合奇偶情况来看,无需考虑j的奇偶性质,均有

dp[i+1][j+1] = dp[i+1][j+1] + dp[i][j]

dp[i+1][j] = dp[i+1][j] + dp[i][j]

B.i放置在当前已生成排列的中间

(1)放置在波峰两端

如图,只会有一个新波峰代替旧波峰,并不会增加或减少拐点数量。即:

dp[i+1][j] = dp[i+1][j] + dp[i][j] *  (波峰数量 * 2);

*2:在波峰的左右两边放置都只是将原波峰变高,不会产生新的波峰

(2)放置在波谷两端

如图,这种情况下,会产生一个新的波峰与波谷。

(3)放置在波峰与波谷中间

如图,这种情况下,会产生一个新的波峰与波谷。

综合(2)、(3)我们可以发现,只要不放置在波峰两边和两个端点处,其余地方放置都会产生两个新拐点,即:

dp[i+1][j+2] = dp[i+1][j+2] + dp[i][j] *  (i - 1 - 波峰数量 * 2);

i - 1:i个点构成i-1端,i - 1个端上可有i-1种放置i的情形

i - 1 - 波峰数量 * 2:i - 1种情形减去波峰左右两种情形【需要明确的是图形必定是波峰波谷交替,因此也不会存在重复减去的情况,因为不可能两个波峰之间有相同的相邻点】

有了上面的知识我们再来做一次梳理,可以明确的是,当增加一个点之后,最多增加两个拐点:

A.偶数个拐点,先谷后峰

不增加拐点: j / 2 * 2 + 1,方案数为(乘法原理):dp[i+1][j] += dp[i][j]*(j/2*2+1)=dp[i][j]*(j+1)

j / 2:波峰数量        *2:波峰左右       +1:最左边

增加一个拐点:2,总方案数为:dp[i+1][j+1] += dp[i][j]*2

增加两个拐点:i + 1 - 2 - (j / 2 * 2 + 1)

i + 1:i个数有i+1个空位,用容斥原理可得增加两个拐点的方案数量

B.偶数个拐点,先峰后谷

不增加拐点: j / 2 * 2 + 1,方案数为(乘法原理):dp[i+1][j] += dp[i][j]*(j/2*2+1)=dp[i][j]*(j+1)

j / 2:波峰数量        *2:波峰左右       +1:最右边

增加一个拐点:2,总方案数为:dp[i+1][j+1] += dp[i][j]*2

增加两个拐点:i + 1 - 2 - (j / 2 * 2 + 1)

i + 1:i个数有i+1个空位,用容斥原理可得增加两个拐点的方案数量

C.奇数个拐点,先谷后峰

不增加拐点: (j - 1) / 2 * 2 + 2,方案数为(乘法原理):dp[i+1][j] += dp[i][j]*(j/2*2+1)=dp[i][j]*(j+1)

(j - 1) / 2:波峰数量        *2:波峰左右       +2:最左边和最右边

增加一个拐点:2,总方案数为:dp[i+1][j+1] += dp[i][j]*2

增加两个拐点:i + 1 - 2 - (j / 2 * 2 + 1)

i + 1:i个数有i+1个空位,用容斥原理可得增加两个拐点的方案数量

D.奇数个拐点,先峰后谷

不增加拐点: (j + 1) / 2 * 2,方案数为(乘法原理):dp[i+1][j] += dp[i][j]*(j/2*2+1)=dp[i][j]*(j+1)

(j + 1) / 2:波峰数量        *2:波峰左右

增加一个拐点:2,总方案数为:dp[i+1][j+1] += dp[i][j]*2

增加两个拐点:i + 1 - (2) - (j / 2 * 2 + 1)

i + 1:i个数有i+1个空位,用容斥原理可得增加两个拐点的方案数量

于是!!!我们会惊讶地发现,这四种情况下,拐点增加的三种情形的公式居然一毛一样,ORZ

整理递推式:

dp[i+1][j] = dp[i+1][j] + dp[i][j]*(j+1)

dp[i+1][j+1] = dp[i+1][j+1] + dp[i][j]*2

dp[i+1][j+2] = dp[i+1][j+2] + dp[i][j]*(i-j-2)

#include <iostream>
using namespace std;
const int mod = 123456;int dp[505][505];int main()
{int n, k, i, j;cin >> n >> k;dp[1][0] = 1;for(i = 2; i <= n; ++ i){dp[i][0] = 2;for(j = 0; j <= i - 2; ++ j){dp[i + 1][j] = (dp[i + 1][j] + dp[i][j] * (j + 1) % mod) % mod;dp[i + 1][j + 1] = (dp[i + 1][j + 1] + dp[i][j] * 2 % mod) % mod;dp[i + 1][j + 2] = (dp[i + 1][j + 2] + dp[i][j] * (i - j - 2) % mod) % mod; }}cout << dp[n][k - 1];return 0;
}

八.解谜游戏

题目描述

小明正在玩一款解谜游戏。谜题由 24 根塑料棒组成,其中黄色塑料棒 4 根,红色 8 根,绿色 12 根 (后面用 Y 表示黄色、R 表示红色、G 表示绿色)。初始时这些塑料棒排成三圈,如上图所示,外圈 12 根,中圈 8 根,内圈 4 根。

小明可以进行三种操作:

  1. 将三圈塑料棒都顺时针旋转一个单位。例如当前外圈从 0 点位置开始顺时针依次是 YRYGRYGRGGGG,中圈是 RGRGGRRY,内圈是 GGGR。那么顺时针旋转一次之后,外圈、中圈、内圈依次变为:GYRYGRYGRGGG、 YRGRGGRR 和 RGGG。

  2. 将三圈塑料棒都逆时针旋转一个单位。例如当前外圈从 0 点位置开始顺时针依次是 YRYGRYGRGGGG,中圈是 RGRGGRRY,内圈是 GGGR。那么逆时针旋转一次之后,外圈、中圈、内圈依次变为:RYGRYGRGGGGY、 GRGGRRYR 和 GGRG。

  3. 将三圈 0 点位置的塑料棒做一个轮换。具体来说:外圈 0 点塑料棒移动到内圈 0 点,内圈 0 点移动到中圈 0 点,中圈 0 点移动到外圈 0 点。例如当前外圈从 0 点位置开始顺时针依次是 YRYGRYGRGGGG,中圈是 RGRGGRRY,内圈是 GGGR。那么轮换一次之后,外圈、中圈、内圈依次变为:RRYGRYGRGGGG、GGRGGRRY 和 YGGR。

小明的目标是把所有绿色移动到外圈、所有红色移动中圈、所有黄色移动到内圈。给定初始状态,请你判断小明是否可以达成目标?

输入描述

第一行包含一个整数 T (1≤T≤100),代表询问的组数。

每组询问包含 3 行:

第一行包含 12 个大写字母,代表外圈从 0 点位置开始顺时针每个塑料棒的颜色。

第二行包含 8 个大写字母,代表中圈从 0 点位置开始顺时针每个塑料棒的颜色。

第三行包含 4 个大写字母,代表内圈从 0 点位置开始顺时针每个塑料棒的颜色。

输出描述

对于每组询问,输出一行 YES 或者 NO,代表小明是否可以达成目标。

输入输出样例

示例

输入

2
GYGGGGGGGGGG
RGRRRRRR
YRYY
YGGGRRRRGGGY
YGGGRRRR
YGGG

输出

YES
NO

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M

思路:本题比较容易想到的思路是BFS,但是这道题的可转移状态实在是太多了,BFS并不是一个很好的解法。实际上,我们观察外中内三个圈,他们的数量分别为12、8、4,我们先做个标记:

我们关注最内层的4根,每次要交换时最多只有4种被换出去的情况,同理,中层与其他层发生交换时,最多只有8种被换出去的情况,类推至外层。

于是我们发现可以交换的塑料棒是按组分的,不同组之间是不可以跨越的。

组0 组1 组2 组3
0 1 2 3
0,4 1,5 2,6 3,7
0,4,8 1,5,9 2,6,10 3,7,11

于是我们可以发现,实际上 编号%4 相同的是处于同一组的。

[值得注意的是,每次交换时,是内中外三层中的同一组,组内各出一个元素进行轮换]

然而我们发现,三个发生交换的组,虽然要求的交换方式是:

外圈 0 点塑料棒移动到内圈 0 点,内圈 0 点移动到中圈 0 点,中圈 0 点移动到外圈 0 点

0点可以通过旋转将同组的点转到0点

似乎交换顺序只能是 外->内->中->外,但是实际上,由于中圈和外圈的组内元素数量>1,因此是可以做到随机交换的。此时我们只需要判断,每一个组里,G、R、Y的分量是否都是总量的1/4就可以了。

#include <iostream>
#include <string>
#include <cstring>
using namespace std;int countG[4], countR[4], countY[4];void countColorNum(string colorSerial)
{for(int i = colorSerial.size() - 1; i >= 0; -- i){switch(colorSerial[i]){case 'G':++ countG[i % 4];break;case 'R':++ countR[i % 4];break;case 'Y':++ countY[i % 4];break;}}
}int main()
{int T;cin >> T;string stringG, stringR, stringY;while(cin >> stringG >> stringR >> stringY){memset(countG, 0, sizeof(countG));memset(countR, 0, sizeof(countR));memset(countY, 0, sizeof(countY));countColorNum(stringG);countColorNum(stringR);countColorNum(stringY);for(int i = 0; i < 4; ++ i){if(countG[i] != 3 || countR[i] != 2 || countY[i] != 1){cout << "NO" << endl;break;}if(i == 3){cout << "YES" << endl;}}}return 0;
}

九.第八大奇迹

题目描述

在一条 R 河流域,繁衍着一个古老的名族 Z。他们世代沿河而居,也在河边发展出了璀璨的文明。

Z 族在 R 河沿岸修建了很多建筑,最近,他们热衷攀比起来。他们总是在比谁的建筑建得最奇特。

幸好 Z 族人对奇特的理解都差不多,他们很快给每栋建筑都打了分,这样评选谁最奇特就轻而易举了。

于是,根据分值,大家很快评出了最奇特的建筑,称为大奇迹。

后来他们又陆续评选了第二奇特、第二奇特、......、第七奇特的建筑,依次称为第二大奇迹、第三大奇迹、......、第七大奇迹。

最近,他们开始评选第八奇特的建筑,准备命名为第八大奇迹。

在评选中,他们遇到了一些问题。

首先,Z 族一直在发展,有的建筑被拆除又建了新的建筑,新建筑的奇特值和原建筑不一样,这使得评选不那么容易了。

其次,Z 族的每个人所生活的范围可能不一样,他们见过的建筑并不是所有的建筑,他们坚持他们自己所看到的第八奇特的建筑就是第八大奇迹。

Z 族首领最近很头疼这个问题,他害怕因为意见不一致导致 Z 族发生分歧。他找到你,他想先了解一下,民众自己认为的奇迹是怎样的。

现在告诉在 R 河周边的建筑的变化情况,以及在变化过程中一些人的生活范围,请编程求出每个人认为的第八大奇迹的奇特值是多少。

输入描述

输入的第一行包含两个整数 L,N,分别表示河流的长度和要你处理的信息的数量。开始时河流沿岸没有建筑,或者说所有的奇特值为 0。

接下来 N 行,每行一条你要处理的信息。

如果信息为 C p x,表示流域中第 p (1≤p≤L) 个位置建立了一个建筑,其奇特值为 x。如果这个位置原来有建筑,原来的建筑会被拆除。

如果信息为 Q a b,表示有个人生活的范围是河流的第 a 到 b 个位置(包含 a 和 b,a≤b),这时你要算出这个区间的第八大奇迹的奇特值,并输出。如果找不到第八大奇迹,输出 0。

其中,1≤L≤10^5,1≤N≤10^5。所有奇特值为不超过10^9的非负整数。

输出描述

对于每个为 Q 的信息,你需要输出一个整数,表示区间中第八大奇迹的奇特值。

输入输出样例

示例

输入

10 15
C 1 10
C 2 20
C 3 30
C 4 40
C 5 50
C 6 60
C 7 70
C 8 80
C 9 90
C 10 100
Q 1 2
Q 1 10
Q 1 8
C 10 1
Q 1 10

输出

0
30

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M

十.燃烧权杖

题目描述

小 C 最近迷上了一款游戏。现在,在游戏中,小 C 有一个英雄,生命值为 x;敌人也有一个英雄,生命值为 y。除此以外,还有 kk 个士兵,生命值分别为 a1​、a2​、......、ak​。

现在小 C 打算使用一个叫做"燃烧权杖"的技能。"燃烧权杖"会每次等概率随机选择一个活着的角色(英雄或士兵),扣减其 10 点生命值,然后如果该角色的生命值小于或等于 0,则该角色死亡,不会再被"燃烧权杖"选中。"燃烧权杖"会重复做上述操作,直至任意一名英雄死亡。

小 C 想知道使用"燃烧权杖"后敌方英雄死亡(即,小 C 的英雄存活)的概率。为了避免精度误差,你只需要输出答案模一个质数 p 的结果,具体见输出描述。

输入描述

输入包含多组数据。

输入第一行包含一个正整数 T,表示数据组数。

接下来 TT 组,每组数据第一行包含四个非负整数 x、y、p、k,分别表示小 C 的英雄的生命值、敌方英雄的生命值,模数和士兵个数。 第二行包含 k 个正整数 a1​、a2​、......、ak​,分别表示每个士兵的生命值。

输出描述

对于每组数据,输出一行一个非负整数,表示答案模质数 p 的余数。

可以证明,答案一定为有理数。设答案为 a/b(a 和 b 为互质的正整数),你输出的数为 x,则你需要保证 a 与 bx 模 p同余;也即,, 其中  表示 b 模 p 的逆元, mod 为取模运算。

输入输出样例

示例

输入

6
1 10 101 0
100 1 101 0
50 30 4903 2
1 1
987 654 233 1
321
1000000000 9999999999 233 3
1 2 3
1000000000 999999999 3 3
1 2 3

输出

51
37
1035
118
117
2

运行限制

  • 最大运行时间:1s
  • 最大运行内存: 256M

思路:首先需要明确的是,本题的胜负条件为两个英雄中任意一位死亡,和士兵是没有关系的,因此本题的士兵为干扰信息,考虑士兵只会让题目更加复杂。

根据英雄血量,我们可以算出,x最多被烧n=x/10+(x%10!=0)次,y最多被烧m=y/10+(y%10!=0)次,要想让x或者,我们可以列出下列几种情况[有点像伯努利分布,第i次结束实验]。对于x和y,每次烧其中一个人的概率是1/2

第几次结束 m m+1 ... m+n-1
发生概率 ...

本题的m、n范围可能很大,求阶乘是不太现实的。需要注意质数p的条件,其实这在暗示我们使用卢卡斯定理进行分解:https://blog.csdn.net/qq_39304630/article/details/77417017

#include <iostream>
using namespace std;
typedef long long ll;ll quickMul(ll A,ll B,ll P)
{ll res = 1;while(B){if(B & 1){res = res * A % P;}B >>= 1;A = A * A % P;}return res;
}ll inv(ll n,ll p) // 费马小定理求解逆元  n^(p-1)=1(mod p)  前提是 n 与 p 互质
{return quickMul(n, p-2, p);
}ll C(ll n,ll r,ll p){if(r > n) return 0;ll res = 1;for(ll i = 1; i <= r; ++ i, -- n){res =  res * n % p * inv(i, p) % p;}return res;
}ll Lucas(ll n,ll r,ll p)
{return r == 0 ? 1 : Lucas(n/p, r/p, p) * C (n%p, r%p, p) % p;
}int main()
{ios::sync_with_stdio(false);cin.tie(0) , cout.tie(0);ll T, x, y, p, k, n, m, buttom, inv_2, ans;cin >> T;while(T --){cin >> x >> y >> p >> k;n = x / 10 + (x % 10 != 0);m = y / 10 + (y % 10 != 0);while(k --){cin >> inv_2;}inv_2 = inv(2, p);ans = 0;for(buttom = m; buttom <= m + n - 1; ++ buttom){ans = (ans + Lucas(buttom - 1, m - 1, p) * quickMul(inv_2, buttom, p)) % p;}cout << ans << endl;}return 0;
}

2019年第十届蓝桥杯B组决赛相关推荐

  1. 2019第十届蓝桥杯A组决赛(国赛)A题(三升序列)

    2019第十届蓝桥杯A组决赛(国赛)A题(三升序列) 输入: VLPWJVVNNZSWFGHSFRBCOIJTPYNEURPIGKQGPSXUGNELGRVZAG SDLLOVGRTWEYZKKXNK ...

  2. 2019年第十届蓝桥杯JAVAB组-----试题 J: 分考场

    题目: [问题背景] 古语有云:春风得意马蹄疾,一日看尽长安花. 当然在一场考试中所有人都春风得意马蹄疾是不可能的,尤其是碰到一些毒瘤出题人的时候. [问题描述] 又到了每月一次的月考,又是 xf 老 ...

  3. 2019年第十届蓝桥杯A组省赛

    A.平方和(5分) 答案:2658417853 试题 A: 平方和 本题总分:5 分 [问题描述] 小明对数位中含有 2.0.1.9 的数字很感兴趣,在 1 到 40 中这样的数包括 1.2.9.10 ...

  4. 2019年第十届蓝桥杯 - 省赛 - C/C++研究生组 - G. 扫地机器人

    2019年第十届蓝桥杯 - 省赛 - C/C++研究生组 - G. 扫地机器人 Ideas 首先我们根据数学常识可以知道,当每个机器人清扫的范围差不多时,最好都是 N / K,花的时间应该是最少的. ...

  5. 2019年第十届蓝桥杯[Java]

    2019年第十届蓝桥杯[Java] 特别数的和 [题目描述] 小明对数位中含有 2.0.1.9 的数字很感兴趣(不包括前导 0),在 1 到 40 中这样的数包括 1.2.9.10 至 32.39 和 ...

  6. 南林蓝桥杯计算机大赛,我院计算机系在2019年第十届蓝桥杯大赛(省赛)中获得5项一等奖...

    我院计算机系在2019年第十届蓝桥杯大赛(省赛)中获得5项一等奖 在刚刚结束的2019年第十届蓝桥杯全国软件和信息技术专业人才大赛(省赛)中,我院计算机系获得了5项一等奖. 软件和信息技术产业作为我国 ...

  7. 第十届蓝桥杯JavaB组省赛真题

    试题 A: 组队 本题总分:5 分 [问题描述] 作为篮球队教练,你需要从以下名单中选出 1 号位至 5 号位各一名球员, 组成球队的首发阵容. 每位球员担任 1 号位至 5 号位时的评分如下表所示. ...

  8. 第十届蓝桥杯JavaC组省赛真题

    试题 A: 求和 本题总分:5 分 [问题描述] 小明对数位中含有 2.0.1.9 的数字很感兴趣,在 1 到 40 中这样的数包 括 1.2.9.10 至 32.39 和 40,共 28 个,他们的 ...

  9. 第十届蓝桥杯单片机组(省赛)——试题解答

    前言 本人曾在第十三届蓝桥杯大赛单片机组中获得国一,以下是我在准备比赛过程中的一些记录,希望能给大家带来帮助 本人持续分享更多关于嵌入式和单片机的知识,如果大家喜欢,别忘点个赞加个关注哦,让我们一起共 ...

最新文章

  1. ROS上同时预览depth,IR,RGB 调试记录
  2. php计算经纬度间的距离
  3. 基于Python操作ElasticSearch
  4. boost::math模块使用 Brent 方法求函数最小值的示例
  5. 团队开发个人总结05
  6. 从远程(包括ftp,http等协议)地址获取文件流信息
  7. python是什么 自学-为什么自学python总是坚持不下去,这篇文章给你解答!
  8. Web API路由与动作(三)
  9. 在线读取office 文件(Word excel 等)
  10. 基于安卓手机的WAPI证书安装使用详解
  11. 高通QCA9531方案定制开发主板300M 2.4G无线模块面板AP wifi路由模块 用的是什么网络变压器
  12. 基于神经网络的图片风格转移小结
  13. php模拟QQ登录获得skey码,PHP模拟QQ网页版授权登陆
  14. JS 把数组按倒序排列
  15. DeepFool论文翻译---DeepFool: a simple and accurate method to fool deep neural networks
  16. reg类型变量综合电路_Verilog中 reg和wire 用法和区别以及always和assign的区别
  17. arch模型的思路_ARCH模型的应用
  18. 关于Linux中的SIGABRT信号
  19. java excel 导出数据文件格式无效
  20. Ubuntu安装过程中出现“没有定义根文件系统”,Ubuntu安装过程中无法读取Windows分区

热门文章

  1. php判断账号英文,php 判断是否是中文/英文/数字示例代码
  2. php四舍五入进一,php 四舍五入的三种方法
  3. 服务器换硬盘关机好还是在线换,服务器硬盘能用多久,多久需要更换新的
  4. ASUS华硕笔记本电脑枪神4P G732LW原装出厂系统恢复原厂系统
  5. spark源码分析之Broadcast
  6. 垃圾分类图像识别API接口,小程序源码
  7. vue3的tsx写法(v-show、v-if、v-for、v-bind、v-on),父子组件传值
  8. 最便宜的html手机,最便宜的骁龙855手机诞生,从2998跌至1299,可惜大家不识货
  9. 让城市生活更美好——大咖谈智慧交通物流与城市治理
  10. 帮我用python做三国杀