比赛信息
题目难度
题目详解
作为一个程序员,这种题目肯定要用不同的姿势解锁O_o
CV姿势1:
#include <stdio.h>
int main()
{
printf(
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO\n"
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO\n"
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO\n"
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO\n"
"OOOOOOooooooooooooooooOOOOOOOOOOOOOO@@OO@@@@@@@@OO@@OOOOOOOOOOOOO\n"
"ooooooooooooooooooooooooooooooOOOO@@ @@ @@ @@OOOOOOOOOOO\n"
"oooooooooooooooooooooooooooooooooo@@ @@OOOOOOOOOOO\n"
"oooooooo..............oooooooooo@@ @@OOOOOOOOOOO\n"
"..............................@@ @@ @@ @@OOOOOOOOO\n"
"......... @@@@ @@OOOOOOOOO\n"
".. @@@@@@@@@@@@@@ @@@@ @@OOOOOOOOO\n"
" @@ @@ @@ @@ @@OOOOOOOOO\n"
" @@@@@@ @@@@@@@@ @@OOOOOOOOO\n"
" @@ @@OOOOOOOOO\n"
" @@ @@OOOOOOOOO\n"
" @@ @@OOOOOOOOO\n"
" ..........@@ @@OOOOOOOOO\n"
"..................@@ @@OOOOOOOOO\n"
"..................@@ @@OOOOOOOOOOO\n"
"......oooooooooooo@@ @@@@ @@@@@@@@ @@@@ @@OOOOOOOOOOO\n"
"oooooooooooooooooo@@ @@OO@@ @@OOOOOO@@ @@@@ @@OOOOOOOOOOO\n"
"oooooooooooooooooooo@@ @@OOOO@@OOOOOOOOOO@@OOOO@@ @@OOOOOOOOOOO\n"
"ooooooOOOOOOOOOOOOOOOO@@OOOOOOOOOOOOOOOOOOOOOOOOOO@@OOOOOOOOOOOOO\n"
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO\n"
"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"
);
return 0;
}
CV姿势2:
#include <iostream>
using namespace std;
int main()
{
cout<<
R"(OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
OOOOOOooooooooooooooooOOOOOOOOOOOOOO@@OO@@@@@@@@OO@@OOOOOOOOOOOOO
ooooooooooooooooooooooooooooooOOOO@@ @@ @@ @@OOOOOOOOOOO
oooooooooooooooooooooooooooooooooo@@ @@OOOOOOOOOOO
oooooooo..............oooooooooo@@ @@OOOOOOOOOOO
..............................@@ @@ @@ @@OOOOOOOOO
......... @@@@ @@OOOOOOOOO
.. @@@@@@@@@@@@@@ @@@@ @@OOOOOOOOO
@@ @@ @@ @@ @@OOOOOOOOO
@@@@@@ @@@@@@@@ @@OOOOOOOOO
@@ @@OOOOOOOOO
@@ @@OOOOOOOOO
@@ @@OOOOOOOOO
..........@@ @@OOOOOOOOO
..................@@ @@OOOOOOOOO
..................@@ @@OOOOOOOOOOO
......oooooooooooo@@ @@@@ @@@@@@@@ @@@@ @@OOOOOOOOOOO
oooooooooooooooooo@@ @@OO@@ @@OOOOOO@@ @@@@ @@OOOOOOOOOOO
oooooooooooooooooooo@@ @@OOOO@@OOOOOOOOOO@@OOOO@@ @@OOOOOOOOOOO
ooooooOOOOOOOOOOOOOOOO@@OOOOOOOOOOOOOOOOOOOOOOOOOO@@OOOOOOOOOOOOO
OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO
OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO)"
<<endl;
return 0;
}
你以为cv很聪明?看题干了没,大佬?这道题是有输入的!你直接读取再输出也可以~
#include <stdio.h>
int main()
{
char str[25][100];
for(int i=0;i<25;i++)
{
gets(str[i]);
printf("%s\n",str[i]);
}
return 0;
}
#include <stdio.h>
int main()
{
printf(
"thinking is important\n"
"stl is useful\n"
"algorithm is useless"
);
return 0;
}
解析:这里就是简单的根据题中所给关系,生成对应的
根据题目的描述,输出数组
matrix[1][i][j]+=matrix[0][i-1][j-1];
matrix[1][i][j]+=matrix[0][i-1][j];
matrix[1][i][j]+=matrix[0][i-1][j+1];
matrix[1][i][j]+=matrix[0][i][j-1];
matrix[1][i][j]+=matrix[0][i][j];
matrix[1][i][j]+=matrix[0][i][j+1];
matrix[1][i][j]+=matrix[0][i+1][j-1];
matrix[1][i][j]+=matrix[0][i+1][j];
matrix[1][i][j]+=matrix[0][i+1][j+1];
这里要注意题目中的一句话:
这句话提示了我们在编程过程中的一种常见错误:
- 为了保证遍历数组时
起始位置 的安全,根据上面的关系,当i=0 和j=0 时,关系式中的i-1 和j-1 的值就是-1 ,那么此时就会引起数组越界导致程序崩溃,所以我们要让计次从i=1 和j=1 开始循环。 - 为了保证遍历数组时
结束位置 的安全,从关系式中可以看到存在i+1 和j+1 ,那么当我们的计次循环来到了第4 次时,i+1 和j+1 的值都是5 ,这也就说明,我们的二维数组的最小成员数是6 ,那么如果我们还是按直觉走,把这个二维数组定义成大小是4 的数组,那么到这个地方就会出现数组越界,导致程序崩溃。
还有一个在编写代码时很容易被忽略的问题:
- 如果在定义数组后,不对数组的成员进行初始化赋值,可能会导致其数值不确定 ( 可能不为
0 ),从而就会导致计算结果出现错误。
由此可以分析得出,通过这种定义方式,题目中要求的:
这里为了记录方便,我将这个数组定义成了三维数组,第一维作为这个矩阵的ID,代表输入的矩阵和转换后输出的矩阵。代码如下:
C语言:
#include <stdio.h>
int main()
{
//初始化数组元素为0,防止数值混乱
int matrix[2][6][6]={0};
for(int i=1;i<=4;i++)
{
for(int j=1;j<=4;j++)
{
scanf("%d",&matrix[0][i][j]);
}
}
for(int i=1;i<=4;i++)
{
for(int j=1;j<=4;j++)
{
matrix[1][i][j]+=matrix[0][i-1][j-1];
matrix[1][i][j]+=matrix[0][i-1][j];
matrix[1][i][j]+=matrix[0][i-1][j+1];
matrix[1][i][j]+=matrix[0][i][j-1];
matrix[1][i][j]+=matrix[0][i][j];
matrix[1][i][j]+=matrix[0][i][j+1];
matrix[1][i][j]+=matrix[0][i+1][j-1];
matrix[1][i][j]+=matrix[0][i+1][j];
matrix[1][i][j]+=matrix[0][i+1][j+1];
printf("%d ",matrix[1][i][j]);
}
printf("\n");
}
return 0;
}
C++:
#include <iostream>
#include <string>
using namespace std;
int main()
{
int matrix[2][6][6]={0};
for(int i=1;i<=4;i++)
{
for(int j=1;j<=4;j++)
{
cin>>matrix[0][i][j];
}
}
for(int i=1;i<=4;i++)
{
for(int j=1;j<=4;j++)
{
int res=0;
for(int x=-1;x<=1;x++)
{
for(int y=-1;y<=1;y++)
{
res+=matrix[0][i+x][j+y];
}
}
cout<<res<<" \n"[j==4];
}
}
return 0;
}
解析:此题目用到了
当然,也可以通过拼凑做,不过这个多少有点不太好想到,下面来简单说一下(Zero学长提供的思路):
先推出中间4个元素,然后把边上的元素搞出来,再搞角落上的元素,列出未知数比较容易看出来:
用上图中
用上图中
代码如下:
#include <stdio.h>
int main()
{
int matrix[2][6][6]={0};
for(int i=1;i<=4;i++)
{
for(int j=1;j<=4;j++)
{
scanf("%d",&matrix[1][i][j]);
}
}
/*--------------矩阵消元求解过程--------------*/
matrix[0][3][3]=(matrix[1][2][2]-matrix[1][2][1])-(matrix[1][1][2]-matrix[1][1][1]);
matrix[0][2][2]=(matrix[1][3][3]-matrix[1][3][4])-(matrix[1][4][3]-matrix[1][4][4]);
matrix[0][2][3]=(matrix[1][3][2]-matrix[1][3][1])-(matrix[1][4][2]-matrix[1][4][1]);
matrix[0][3][2]=(matrix[1][2][3]-matrix[1][2][4])-(matrix[1][1][3]-matrix[1][1][4]);
matrix[0][3][1]=matrix[1][2][2]-matrix[1][1][2]-matrix[0][3][2]-matrix[0][3][3];
matrix[0][2][1]=matrix[1][3][2]-matrix[1][4][2]-matrix[0][2][2]-matrix[0][2][3];
matrix[0][1][2]=matrix[1][2][3]-matrix[1][2][4]-matrix[0][2][2]-matrix[0][3][2];
matrix[0][1][3]=matrix[1][2][2]-matrix[1][2][1]-matrix[0][2][3]-matrix[0][3][3];
matrix[0][2][4]=matrix[1][3][3]-matrix[1][4][3]-matrix[0][2][2]-matrix[0][2][3];
matrix[0][3][4]=matrix[1][2][3]-matrix[1][1][3]-matrix[0][3][2]-matrix[0][3][3];
matrix[0][4][2]=matrix[1][3][3]-matrix[1][3][4]-matrix[0][2][2]-matrix[0][3][2];
matrix[0][4][3]=matrix[1][3][2]-matrix[1][3][1]-matrix[0][2][3]-matrix[0][3][3];
matrix[0][1][1]=matrix[1][1][1]-matrix[0][1][2]-matrix[0][2][1]-matrix[0][2][2];
matrix[0][1][4]=matrix[1][1][4]-matrix[0][1][3]-matrix[0][2][3]-matrix[0][2][4];
matrix[0][4][1]=matrix[1][4][1]-matrix[0][3][1]-matrix[0][3][2]-matrix[0][4][2];
matrix[0][4][4]=matrix[1][4][4]-matrix[0][4][3]-matrix[0][3][4]-matrix[0][3][3];
/*--------------矩阵消元求解过程--------------*/
for(int i=1;i<=4;i++)
{
for(int j=1;j<=4;j++)
{
printf("%d ",matrix[0][i][j]);
}
printf("\n");
}
return 0;
}
解析:这道题目考察位运算中的
由题目中给出的美丽值
所以,我们只需要将数组中所有的数字进行异或运算,得出来的结果就是美丽值
代码如下:
#include <stdio.h>
int main()
{
int count=0;
int res=0;
scanf("%d",&count);
while(count--)
{
int num=0;
scanf("%d",&num);
res^=num;
}
printf("%d",res);
return 0;
}
解析:该题目也是对二进制位运算的考察,以及对于二进制数的一些性质的考察。
小知识:2的幂的二进制形式中,
那么我们如何来判断一个数的二进制里只有一个
首先我们来观察一下下面这张图上,这些数字的二进制特点:
从以上数字中,我们可以发现,2的幂二进制中只有一位是
那么下面我们来说说按位与 (&) :
按位与就是将整数从十进制转化为二进制数,上下按位比较,在这个位置上只要有
Bin1 | 0 | 0 | 1 | 1 | 0 | 1 | 0 | 1 |
Bin2 | 0 | 1 | 0 | 1 | 1 | 1 | 0 | 0 |
&(按位与后) | 0 | 0 | 0 | 1 | 0 | 1 | 0 | 0 |
那么通过按位与,再结合2的幂与其减一后数字二进制的关系,我们可以得到以下过程:
24=16 (BIN) | 0 | 0 | 0 | 1 | 0 | 0 | 0 | 0 |
16-1=15 (BIN) | 0 | 0 | 0 | 0 | 1 | 1 | 1 | 1 |
&(按位与后) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
25=32 (BIN) | 0 | 0 | 1 | 0 | 0 | 0 | 0 | 0 |
32-1=31 (BIN) | 0 | 0 | 0 | 1 | 1 | 1 | 1 | 1 |
&(按位与后) | 0 | 0 | 0 | 0 | 0 | 0 | 0 | 0 |
由此我们可以得出一个结论:设正整数
代码如下:
#include <stdio.h>
int main()
{
int count=0;
int res=0;
scanf("%d",&count);
while(count--)
{
int num=0;
scanf("%d",&num);
if(!((num)&(num-1)))
{
res++;
}
}
printf("%d",res);
return 0;
}
解析:使用标准输入输出函数读入IP地址的四个字段整数,然后依次按其八位二进制输出即可。此处使用C++中的
代码如下:
C语言:
#include <stdio.h>
#include <stdlib.h>
void ToBinary(int num) {
for (int i = 7; i >= 0; i--) {
int bit = (num >> i) & 1;
printf("%d", bit);
}
}
int main()
{
int nums[4];
scanf("%d.%d.%d.%d",&nums[0],&nums[1],&nums[2],&nums[3]);
for(int i=0;i<4;i++)
{
ToBinary(nums[i]);
}
return 0;
}
C++:
#include <iostream>
#include <bitset>
using namespace std;
int main()
{
int nums[4];
for(int i=0;i<4;i++)
{
//ignore的作用是忽略输入IP时的小数点
cin>>nums[i];cin.ignore();
//bitset<8>可以将十进制数转化为八位二进制
cout<<bitset<8>(nums[i]);
}
cout<<endl;
return 0;
}
解析:很多人估计看到死长死长的题干,以为这是模拟题,但其实这道题目的解法,很数学!
首先我们分析题目最后给的平均每秒伤害ADPS的公式:
如上图所示的法杖有 5 个火花弹和 1 个修正法术,这个修正法术的
- 一个周期内所有法术修正后的伤害之和 = 3*
(修正法术左边的火花弹数量) + 13*(修正法术右边的火花弹数量) - 一个周期内所有法术的释放延迟所需时间之和 = 0.05*
(修正法术左边的火花弹数量) + 0.10*(修正法术右边的火花弹数量) - 法杖充能时间 = 0.05
- 则平均每秒伤害 ADPS = (3*
2 + 13*3 ) / (0.05*2 + 0.10*3 + 0.05) = 100
请你注意我在公式中标红的地方,由题目可知,
我们设
修正法术左边的火花弹的伤害为
那么一个周期内所有法术修正后的伤害之和=
一个周期内所有法术的释放延迟所需时间之和(外加法杖充能时间)=
由此,我们可以得到一个关于
对其进行
代码如下:
#include <stdio.h>
int main() {
int T;
scanf("%d", &T);
for (int t = 0; t < T; t++) {
int n, m;
scanf("%d %d", &n, &m);
double res=n*(3+10*m)/(0.05*n*(m+1)+0.05);
printf("%.2lf\n",res);
}
return 0;
}
解析:此题目关键在于寻找与这个数字相邻最近且最小的
根据题意,如果这个数本身就是
首先我们需要先定义判断质数的函数:
int is_prime(int num) {
if (num < 2) {
return 0;
}
for (int i = 2; i * i <= num; ++i) {
if (num % i == 0) {
return 0;
}
}
return 1;
}
接着我们定义一个函数原型为
- 首先判断输入的数是否是
质数 ,如果是质数 ,就返回其本身 - 接着我们定义
两个整形变量 ,一个依次递减 ,一个依次递增 ,分别代表其左右两边的数 - 使用while,判断递减或递增后的数是否是质数,如果两个都不是质数,那么就继续递减或递增;如果其中一个是质数,首先判断递减的数值是否是质数,如果是,就返回递减的数值,如果不是,就返回递增的数值。这样就保证了返回的数一定是最小的。
接着我们就可以根据题目要求,填入相应的参数,之后把结果相乘,即可得到答案。
代码如下:
C语言:
#include <stdio.h>
int is_prime(int num) {
if (num < 2) {
return 0;
}
for (int i = 2; i * i <= num; ++i) {
if (num % i == 0) {
return 0;
}
}
return 1;
}
int near_prime(int x) {
//首先判断输入的数是否是质数
if (is_prime(x)) {
return x;
}
//定义两个整形变量,一个依次递减,一个依次递增,分别代表其左右两边的数
int lower = x - 1;
int upper = x + 1;
//判断递减或递增后的数是否是质数,如果两个都不是质数,那么就继续递减或递增
while (!is_prime(lower) && !is_prime(upper)) {
lower--;
upper++;
}
//如果其中一个是质数,首先判断递减的数值是否是质数,如果是,就返回递减的数值,如果不是,就返回递增的数值
if (is_prime(lower)) {
return lower;
} else {
return upper;
}
}
int solve() {
int x;
scanf("%d", &x);
int prime1 = near_prime(x);
int prime2 = near_prime(97 - x);
printf("%d", prime1 * prime2);
}
int main() {
solve();
return 0;
}
C++:
#include <iostream>
bool is_prime(int num) {
if (num < 2) return false;
for (int i = 2; i * i <= num; ++i)
if (num % i == 0) return false;
return true;
}
int near_prime(int x) {
//首先判断输入的数是否是质数
if (is_prime(x)) return x;
//定义两个整形变量,一个依次递减,一个依次递增,分别代表其左右两边的数
int lower = x - 1;
int upper = x + 1;
//判断递减或递增后的数是否是质数,如果两个都不是质数,那么就继续递减或递增
while (!is_prime(lower) && !is_prime(upper)) lower--, upper++;
//如果其中一个是质数,首先判断递减的数值是否是质数,如果是,就返回递减的数值,如果不是,就返回递增的数值
if (is_prime(lower)) return lower;
else return upper;
}
void solve() {
int x;
std::cin >> x;
int prime1 = near_prime(x);
int prime2 = near_prime(97 - x);
std::cout << prime1*prime2 << std::endl;
}
int main() {
solve();
return 0;
}
求方案数,用到动态规划的思想,话不多说,直接上图:
样例给出了如图字符串,让我们求有多少种方案能拾起ACM,我们只能按顺序捡,所以上图有两种拾起方案。分别如下:
OK,然后我们对样例分析,我们只能按顺序捡起ACM,逐个分析,我们把这串字符串成为S,S1是A,S2是C,依次类推。我们在S1处捡到了A,在S2处捡到了C,最后只能在S3或S5处捡到C,所以只有俩种方案,因为我们不可能在S4处捡到A再返回去S2处找C。
我们来换一个样例:
猜一猜有几种
答案是五种:
仔细观察,我们不难发现,每一个C都可以由前面的A转移过来,每一个M都可以由前面的C转移过来,
由此我们就可以得出答案了,只要求出所有的M能从多少个C中转移过来,那么就是答案了。
代码如下:
C语言:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int len=0,a=0,c=0,res=0;
scanf("%d",&len);
char* str=(char*)malloc(len*sizeof(char));
scanf("%s",str);
for(int i=0;i<len;i++)
{
if(str[i]=='A') a++;
if(str[i]=='C') c+=a;
if(str[i]=='M') res+=c;
}
printf("%d",res);
return 0;
}
C++:
#include <iostream>
#include <string>
using namespace std;
int main()
{
int len=0,a=0,c=0,res=0;
cin>>len;
string str;cin>>str;
for(auto temp:str)
{
if(temp=='A') a++;
if(temp=='C') c+=a;
if(temp=='M') res+=c;
}
cout<<res<<endl;
return 0;
}
dp状态转移方程:
#include <stdio.h>
#include <string.h>
#define MOD 1000000007 //不取模数据会溢出
void solve(int n, char *s) {
char target[] = "ACM";
int dp[n + 1][4];
memset(dp, 0, sizeof(dp));
for (int i = 0; i <= n; i++) {
dp[i][0] = 1;
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= 3; j++) {
dp[i][j] = dp[i - 1][j];
if (s[i - 1] == target[j - 1]) {
dp[i][j] = (dp[i][j] + dp[i - 1][j - 1]) % MOD;
}
}
}
printf("%d", dp[n][3]);
}
int main() {
int n;
scanf("%d", &n);
char s[n];
scanf("%s", s);
solve(n, s);
return 0;
}
本次题目解析没有参考官方题解,如若出现错误,请及时评论或私信指出~
暂无评论内容