昨天下午,我简单地看了下蓝桥杯省赛模拟赛的题。硬生生地应付完了,结果拿了 34/1000+ 名,不知道是惊喜还是惊吓?
题目来源:https://www.jisuanke.com/contest/1215
给你一个从n*n的矩阵,里面填充1到n*n。例如当n等于3的时候,填充的矩阵如下。
1 2 3
4 5 6
7 8 9
现在我们把矩阵中的每条边的中点连起来,这样形成了一个新的矩形,请你计算一下这个新的矩形的覆盖的数字的和。比如,n=3的时候矩形覆盖的数字如下。
2
4 5 6
8
那么当n等于101的时候,矩阵和是多少?
把题目读错了,以为是求中点连成的十字架数字之和,其实非也,是类似菱形覆盖的数字之和。以矩形的中心((N-1)/2, (N-1)/2)为原点,菱形中数字的横纵坐标之和到原点的距离小于或等于矩形半径。
代码
#include
#include
#define N 101
int main(void)
{
int index = 0;
long long int sum = 0L;
for(int i = 0;i < N;i++)
{
for(int j = 0;j < N;j++)
{
++index;
if(abs((i-(N-1)/2))+abs((j-(N-1)/2)) <= (N-1)/2)
{
sum += index;
//printf("%d\n", index);
}
}
}
printf("%lld\n", sum);
return 0;
}
答案:26020201
用0,1,2,3…7这8个数字组成的所有整数中,质数有多少个(每个数字必须用到且只能用一次)。
提示:以0开始的数字是非法数字。
暴力枚举所有数字,并判断
代码
#include
#include
int main(void)
{
int cnt = 0;
for(int a = 1;a < 8;a++)
for(int b = 0;b < 8;b++)
for(int c = 0;c < 8;c++)
for(int d = 0;d < 8;d++)
for(int e = 0;e < 8;e++)
for(int f = 0;f < 8;f++)
for(int g = 0;g < 8;g++)
for(int h = 0;h < 8;h++)
{
if(a!=b && a!=c && a!=d && a!=e && a!=f && a!=g && a!=h
&& b!=c && b!=d && b!=e && b!=f && b!=g && b!=h
&& c!=d && c!=e && c!=f && c!=g && c!=h
&& d!=e && d!=f && d!=g && d!=h
&& e!=f && e!=g && e!=h
&& f!=g && f!=h
&& g!=h)
{
int i = a*10000000+b*1000000+c*100000+d*10000+e*1000+f*100+g*10+h;
bool flag = true;
for(int k = 2;k <= sqrt(i)+0.5;k++)
{
if(i%k == 0)
{
flag = false;
break;
}
}
if(flag)
{
cnt++;
}
}
}
printf("%d\n",cnt);
return 0;
}
答案:2668
1 |
4 |
2 |
5 |
2 |
1 |
2 |
1 |
3 |
1 |
3 |
2 |
2 |
5 |
3 |
4 |
我们可以把任意两个在图的边界上相同的方格一起消掉,每次消掉两个方格的时候,都会获得一个分数,第i次消的分数为i*方格的值。
请你帮忙最优操作情况下,获得的分数最多为多少。
DFS搜索
答案:89
一个数的整数次幂,是我们在计算中经常用到的,但是怎么可以在O(log(n))的时间内算出结果呢?
代码框中的代码是一种实现,请分析并填写缺失的代码,求xymod p 的结果。
#include
using namespace std;
int pw(int x, int y, int p) {
if (!y) {
return 1;
}
int res = /*在这里填写必要的代码*/;
if (y & 1) {
res = res * x % p;
}
return res;
}
int main() {
int x, y, p;
cin >> x >> y >> p;
cout << pw(x, y, p) << endl;
return 0;
}
答案:pw(x,y>>1,p)*pw(x,y>>1,p)%p(或者pw(x,y/2,p)*pw(x,y/2,p)%p)
N!末尾有多少个0呢?
N! = 1*2*…*N。
代码框中的代码是一种实现,请分析并填写缺失的代码。
#include
using namespace std;
int main() {
int n, ans = 0;
cin >> n;
while (n) {
ans += /*在这里填写必要的代码*/;
}
cout << ans << endl;
return 0;
}
答案:(n/=5)
蒜头君得到一张藏宝图。藏宝图是一个10*10 的方格地图,图上一共有10 个宝藏。有些方格地形太凶险,不能进入。
整个图只有一个地方可以出入,即是入口也是出口。蒜头君是一个贪心的人,他规划要获得所有宝藏以后才从出口离开。
藏宝图上从一个方格到相邻的上下左右的方格需要1 天的时间,蒜头君从入口出发,找到所有宝藏以后,回到出口,最少需要多少天。
自己手算的,注意最后要回到出入点
答案:48
蒜头君得到了 n 个数,他想对这些数进行下面这样的操作,选出最左边的相邻的差的绝对值为 1 的两个数,只保留较小的数,删去较大的数,直到没有两个相邻的差的绝对值为 1 的数,问最多可以进行多少次这样的操作?
输入第一行为一个整数 n(1≤n ≤ 105),表示数字的总数
第二行为 n 个整数 x1,x2,...,xn (0≤xi≤10),表示这些数。
输出一行,为一个整数,表示蒜头君最多可以进行多少次这样的操作。
4
1 2 0 1
3
第一次使用的是暴力法,一直反复检测到所有数据全部一致就OK,但是只能通过一组数据,其余九组全部超时。于是改用栈来维护合并的数。
代码
#include
#include
using namespace std;
int main(void)
{
int n;
scanf("%d", &n);
stack s;
int cnt = 0;
for(int i = 0;i < n;i++)
{
int a;
scanf("%d", &a);
while(!s.empty() && s.top() - a == 1)
{
s.pop();
cnt ++;
}
if(!s.empty() && a - s.top() == 1)
{
cnt ++;
}
else
{
s.push(a);
}
}
printf("%d\n", cnt);
return 0;
}
注意:while(!s.empty() && s.top() - a == 1)使用的是while,一直以为if也可以,但是过不了数据3 3 3 3 2。
蒜头君喜欢下棋。最近它迷上了国际象棋。国际象棋的棋盘可以被当做一个 8*8 的矩阵,棋子被放在格子里面(不是和中国象棋一样放在线上)。
蒜头君特别喜欢国际象棋里面的马,马的移动规则是这样的:横着走两步之后竖着走一步,或者横着走一步之后竖着走两步。例如,一匹马在 (3,3) 的位置,则它可以到达的地方有 (1,2), (2,1), (1,4),(4,1), (5,2), (2,5), (5,4), (4,5) 八个地方。蒜头君想要把整个棋盘都放上马,并且让这些马不能相互攻击(即任何一匹马不能走一步之后就到达另一匹马的位置)。蒜头君当然知道在 8 *8 的棋盘上怎么放马,但如果棋盘变为 n*m 的,蒜头君就不懂了。他希望你来帮忙他计算一下究竟能放多少匹马。
共一行,两个整数n和m( 1≤n , m≤1000),代表棋盘一共有 n 行 m 列。
输出一个整数,代表棋盘上最多能放的马的数量。
2 4
4
3 4
6
假设行数n <= 列数m,
当行数n=1时,最大放马数为列数m;
当行数n=2时,最大放马数为放两列空两列(注意如何计算);
当行数n>2时,最大方马数为国际棋盘样式(注意要m*n+1);
代码
#include
#include
using namespace std;
int main(void)
{
int n, m;
scanf("%d%d", &n,&m);
if(n > m)
{
int t = n;
n = m;
m = t;
}
if(n == 1)
{
printf("%d\n", m);
}
else if(n == 2)
{
printf("%d\n", m/4*4+min(m%4,2)*2);
}
else
{
printf("%d\n", (n*m+1)/2);
}
return 0;
}
今天蒜头君拿到了一个数轴,上边有 n 个点,但是蒜头君嫌这根数轴不够优美,想要通过加一些点让它变优美,所谓优美是指考虑相邻两个点的距离,最多只有一对点的距离与其它的不同。
蒜头君想知道,他最少需要加多少个点使这个数轴变优美。
输入第一行为一个整数 n(1≤n≤105),表示数轴上的点数。
第二行为 nn 个不重复的整数 x1,x2,...,xn(−109≤xi≤109),表示这些点的坐标,点坐标乱序排列。
输出一行,为一个整数,表示蒜头君最少需要加多少个点使这个数轴变优美。
4
1 3 7 15
1
不会
蒜头君特别喜欢数学。今天,蒜头君突发奇想:如果想要把一个正整数 n 分解成不多于 k 个正整数相加的形式,那么一共有多少种分解的方式呢?
蒜头君觉得这个问题实在是太难了,于是他想让你帮帮忙。
共一行,包含两个整数 n (1≤n≤300) 和 k (1≤k≤300),含义如题意所示。
一个数字,代表所求的方案数。
5 3
5
之前采用的循环+递归,过了大半样例,其余超时,后改用纯递归,超时更严重了……就用循环吧!注意结果使用longlong int来保存,不然会爆!
当n=1 || k=1时,f(n, k) = 1;
当n < k 时,f(n, k) = f(n, n);
当n = k 时,f(n, k) = f(n, k-1) + 1;
当n > k 时,f(n ,k) = f(n, k-1) + f(n-k, k);
循环+递归代码(超时)
#include
int f(int n,int k)
{
if(n == k) return 1;
if(n < k) return 0;
if(n == 1 || k == 1) return 1;
return f(n-1,k-1)+f(n-k,k);
}
int main(void)
{
int n,k;
scanf("%d%d", &n,&k);
int res = 0;
for(int i = 1;i <= k;i++)
{
res += f(n,i);
}
printf("%d\n", res);
return 0;
}
纯循环
#include
int main(void)
{
int n,k;
long long int a[320][320];
scanf("%d%d", &n, &k);
for(int i = 1;i <= n;i++)
{
for(int j = 1;j <= k;j++)
{
if(i == 1 || j == 1)
a[i][j] = 1;
if(i < j)
a[i][j] = a[i][i];
if(i == j)
a[i][j] = a[i][j-1] + 1;
if(i > j)
a[i][j] = a[i][j-1] + a[i-j][j];
}
}
printf("%lld\n", a[n][k]);
return 0;
}