试题链接:A-J题题面
如果想对着题目一边看题面一边看题解,可以尝试分屏,很方便,快捷键:win+← win+→ 之所以在标题中加入易懂二字是因为博主自己对算法也不怎么懂,我放出来的题解一定是我自己弄懂之后的比较简单的题解,所以是比较适合小白或者初学者看的,如果有任何的疑惑或者建议、意见都可以在评论区回复我
我使用的头文件#include<bits/stdc++.h>是万能头文件 通常写这一个就可以了
题解:
试题A:门牌制作
解题思路:
一个主循环体从1循环到2020
用abcd记录i的每一位的数字
若数字中有2 则res++
用四个if语句的目的是防止漏掉答案
解题代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int res=0,a,b,c,d;
for(int i=1;i<=2020;i++)
{
a=i/1000;
b=(i-a*1000)/100;
c=(i-a*1000-b*100)/10;
d=i-a*1000-b*100-c*10;
if(a==2)
res++;
if(b==2)
res++;
if(c==2)
res++;
if(d==2)
res++;
}
cout<<res<<endl;
return 0;
}
//624
更简洁的代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int res=0;
for(int i=1;i<=2020;i++)
{
int j=i;
while(j)
{
if(j%10==2)
res++;
j/=10;
}
}
cout<<res<<endl;
return 0;
}
试题B:既约分数
解题思路:
两层循环的嵌套,值得一说的是函数__gcd()的使用:
__gcd(x,y)是GNU的内部函数,不是一个标准库里的函数,平时写题直接用这个函数挺方便的,int、long long类型都可以,需要注意的是两个类型必须要相同,还有就是不能用浮点型,当然也可以手写gcd函数,它头文件是algorithm
解题代码:
#include<bits/stdc++.h>
using namespace std;
int main()
{
int res=0;
for(int i=1;i<=2020;i++)
{
for(int j=1;j<=2020;j++)
{
if(__gcd(i,j)==1)
res++;
}
}
cout<<res<<endl;
return 0;
}
//2481215
试题C:蛇形填数
解题思路:
其实这一题在比赛时我并没有写程序而是找规律找出来的,对角线位置的值是1 5 13 每次都是加4的倍数 +4 +8 +12 +16…这样算个几次就到了20 所以比赛时我发现这个规律后就直接算出来了,没有写程序,当然作为学习还是需要写代码的 这种投机取巧只能关键时刻用一用
正经思路:根据题意,找出规律,主要顺着对角线上数字递增的方向看:行数从1开始算,当行数为奇数时,行数值比列数值大1的位置的数值小,即右上角大于左下角,沿着对角线向上递增;当行数为偶数时,行数值比列数值大1的位置数值大,即右上角小于左下角,沿着对角线向下递增;可以观察从(3,3)位置和(4,4)位置开始的对角线。
得出行列变化的规律,顺着这样的规律跟随行列值得变化递增每个位置的值。
i&1的意义是判断i的奇偶性,类似i%2但是用位运算会快很多,听说位运算可以提升60%的效率,要养成多用位运算的习惯
具体实现细节看代码:
解题代码:
#include <bits/stdc++.h>
using namespace std;
int a[50][50];
int main() {
int num = 40 * 40;
for(int i = 1, cnt = 1; i <= 40 && cnt <= num; i++) {
if(i & 1) //偶数行时
{
for(int x = i, y = 1; x >= 1 && y <= i; x--, y++)
{
a[x][y] = cnt++;
}
}
else//奇数行时
{
for(int x = 1, y = i; x <= i && y >= 1; x++, y--)
{
a[x][y] = cnt++;
}
}
}
cout<<a[20][20]<<endl;
return 0;
}
//761
试题D:跑步锻炼
解题思路:直接按题意进行日期的循环,然后判断
解题代码:
#include<bits/stdc++.h>
using namespace std;
int month[13]={0,31,0,31,30,31,30,31,31,30,31,30,31};
int f(int year)
{
if(year%400==0||(year%4==0&&year%100!=0))//闰年
month[2]=29;
else
month[2]=28;
}
int main()
{
int y=2000,m=1,d=1,week=6,ans=2;
while(y!=2020||m!=10||d!=1)//2020&&10&&1整体取反
{
f(y);
d++;
week=(week+1)%7;
if(d>month[m])//一个月轮完
{
d=1;//天数重置 月份加一
m++;
if(m>12)//一年轮完
{
m=1;//月份重置 年份加一
y++;
}
}
if(d==1||week==1)
ans+=2;
else
ans++;
}
cout<<ans<<endl;
return 0;
}
试题E:七段码
解题思路:实际上就是求连通图的子图数目,涉及到图,并查集和深度搜索相关知识点不了解的可以直接在CSDN上搜索充电,在此就不多加赘述,有很多博主都解释的很通俗易懂
解题代码:
#include <bits/stdc++.h>
using namespace std;
int mp[8][8]; //连通图
int flag[8]; //标记该点是否被访问过 1表示灯亮着 一共7个灯 1表示亮着 0表示熄的
int father[8];//把该点放入数组
int result = 0;
void creat(){
for (int i = 1; i < 8; i++){
for (int j = 1; j < 8; j++){
mp[i][j] = 0;
}
}
mp[1][2] = mp[1][6] = 1;//用数组表示连通图
mp[2][1] = mp[2][3] = mp[2][7] = 1;
mp[3][2] = mp[3][4] = mp[3][7] = 1;
mp[4][3] = mp[4][5] = 1;
mp[5][4] = mp[5][6] = mp[5][7] = 1;
mp[6][1] = mp[6][5] = mp[6][7] = 1;
mp[7][2] = mp[7][3] = mp[7][5] = mp[7][6] = 1;
}
int find(int i){//查找并查集中的根
if(father[i] == i) return i;
return find(father[i]);
}
void dfs(int i){
if (i == 8){//判断边界
for (int m = 1; m <= 7; m++){
father[m] = m; //把自己设为自己的父节点
}
for (int i = 1; i <= 7; i++){ //遍历每一种情况 构造并查集
for (int j = 1; j <= 7; j++){
if (mp[i][j] && flag[i] && flag[j]){//check满足
//将连通且亮着的灯并在一块
int x = find(i);
int y = find(j);
if (x != y) {
father[x] = y;
}
}
}
}
int cnt = 0; //根的个数
for (int i = 1; i<= 7; i++){//有几个根就有几个集合
if (flag[i] && father[i] == i) cnt++; //亮着的灯的集合数
}
if (cnt == 1) result++;//都连通的话就只有一个结合符合要求
return ;
}
flag[i] = 1;//i灯亮 dfs中i+1亮和灭 标记
dfs(i + 1);//继续搜索
flag[i] = 0;//i灯灭
dfs(i + 1); //这一句不能少,这种情况为该灯熄灭的情况
int main(){
//建图
creat();
//深搜
dfs(1);
cout << result << endl;
return 0;
}
试题F:成绩统计
解题思路:很简单不多说,唯一需要注意的就是输出的细节控制,代码中用了两种方法都是可以的
解题代码:
#include<bits/stdc++.h>
using namespace std;
#define max 10010
int main()
{
int n,a[max],you=0,jige=0;
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
for(int i=0;i<n;i++)
{
if(a[i]>=85)
you++;
if(a[i]>=60)
jige++;
}
/*double ans1=(double)you/(double)n;
double ans2=(double)jige/(double)n;
int res1=int(ans1*1000+5)/10;
int res2=int(ans2*1000+5)/10;
printf("%d%\n%d%\n",res2,res1);*/
printf("%.0f%\n%.0f%%\n",(double)jige*100.0/n,(double)you*100.0/n);
return 0;
}
试题G:回文日期
解题思路:题意也比较好理解,就是代码稍微有点繁琐
解题代码:
#include <bits/stdc++.h>
using namespace std;
int MONTH[13] = {0, 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
//判断是否为闰年
int f(int year)
{
if (year % 400 == 0 || (year % 4 == 0 && year % 100))
MONTH[2] = 29;
else
MONTH[2] = 28;
}
char s[10];
//判断是否是回文数
bool check1(int y, int m, int d)
{
char s1[10];
s1[0] = y / 1000 % 10 + '0';//八位数分别转化为数字
s1[1] = y / 100 % 10 + '0';
s1[2] = y / 10 % 10 + '0';
s1[3] = y / 1 % 10 + '0';
s1[4] = m / 10 % 10 + '0';
s1[5] = m / 1 % 10 + '0';
s1[6] = d / 10 % 10 + '0';
s1[7] = d / 1 % 10 + '0';
if (s1[0] == s1[7] && s1[1] == s1[6] && s1[2] == s1[5] && s1[3] == s1[4])
return 1;
return 0;
}
//判断是否是ABABBABA型的回文数
bool check2(int y, int m, int d)
{
char s1[10];
s1[0] = y / 1000 % 10 + '0';
s1[1] = y / 100 % 10 + '0';
s1[2] = y / 10 % 10 + '0';
s1[3] = y / 1 % 10 + '0';
s1[4] = m / 10 % 10 + '0';
s1[5] = m / 1 % 10 + '0';
s1[6] = d / 10 % 10 + '0';
s1[7] = d / 1 % 10 + '0';
if (s1[0] == s1[2] && s1[2] == s1[5] && s1[5] == s1[7] && s1[0] != s1[1] && s1[1] == s1[3] && s1[3] == s1[4] && s1[4] == s1[6])
return 1;
return 0;
}
int main()
{
scanf("%s", s);
int y, m, d;
//获取年月日
y = (s[0] - '0') * 1000 + (s[1] - '0') * 100 + (s[2] - '0') * 10 + (s[3] - '0');
m = (s[4] - '0') * 10 + s[5] - '0';
d = (s[6] - '0') * 10 + s[7] - '0';
int f1 = 0, f2 = 0;
while (!f1 || !f2)//都找到了的情况下才会停止循环
{
f(y);
d++;
if (d > MONTH[m])//一个月轮完
{
d = 1;//天数重置
m++;//月份++
if (m > 12)//一年轮完
{
m = 1;//月份重置
y++;//年份++
}
}
if (check1(y, m, d) && !f1)//!f1保证是第一次找到
{
f1 = 1;
printf("%04d%02d%02d\n", y, m, d);
}
if (check2(y, m, d) && !f2)
{
f2 = 1;
printf("%04d%02d%02d\n", y, m, d);
}
}
return 0;
}
试题H:子串分值和
解题代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int last[30], n;
char str[N];
int main() {
scanf("%s", str + 1);
n = strlen(str + 1);
ll ans = 0;
for(int i = 1; i <= n; i++) {
ans += 1ll * (i - last[str[i] - 'a']) * (n - i + 1);
last[str[i] - 'a'] = i;
}
printf("%lld\n", ans);
return 0;
}
试题I:平面切分
解题代码:
#include<bits/stdc++.h>
using namespace std;
const int N = 1005;
int main()
{
int n;
scanf("%d", &n);
int a, b;
long double A[N], B[N];
pair<long double, long double> p;
set<pair<long double, long double> > s; //利用set自动去重功能筛选掉重边
for(int i = 0; i < n; i++)
{
scanf("%d %d", &a, &b);
p.first = a;
p.second = b;
s.insert(p);
}
int i = 0; //将去重后的直线数据放回A,B数组
for(set<pair<long double, long double> >::iterator it = s.begin(); it != s.end(); it++, i++)
{
A[i] = it -> first;
B[i] = it -> second;
}
long long ans = 2; //初始情况当只有一条直线时,有两个平面
for(int i = 1; i < s.size(); i++) //从下标1开始,也就是第二条直线
{
set<pair<long double, long double> > pos; //记录第i条直线与先前的交点
for(int j = i-1; j >= 0; j--)
{
int a1 = A[i], b1 = B[i];
int a2 = A[j], b2 = B[j];
if(a1 == a2) //遇到平行线无交点,跳出
continue;
p.first = 1.0*(b2-b1)/(a1-a2);
p.second = 1.0*a1*((b2-b1)/(a1-a2)) + b1;
pos.insert(p);
}
ans += pos.size() + 1; //根据结论,每增加一条直线,对平面数的贡献值是其与先前直线的交点数(不重合)+1
}
printf("%d\n", ans);
return 0;
}
试题J:字串排序
解题代码:
#include<bits/stdc++.h>
using namespace std;
#define _for(i, a, b) for (int i = (a); i < (b); ++i)
#define _rep(i, a, b) for (int i = (a); i <= (b); ++i)
#define For(i, a, b) for (int i = (a); i >= (b); --i)
#define debug(a) cout << #a << " = " << a << endl;
#define mod(x) (x) % MOD
#define ENDL "\n"
typedef long long ll;
typedef pair<int, int> pii;
typedef pair<double, double> pdd;
typedef vector<int> vi;
const int N = 200 + 10, M = 30;
int f[N][M], n;
void get(int& a, int& b) {
_for(i, 0, N) _rep(j, 1, 26) if (f[i][j] >= n) {
a = i, b = j;
return;
}
}
int main()
{
#ifdef LOCAL
freopen("data.in", "r", stdin);
#endif
ios::sync_with_stdio(false);
cout.tie(0), cin.tie(0);
memset(f, -0x3f, sizeof f), f[0][0] = 0;
cin >> n;
_for(i, 0, N) _rep(j, 1, 26) _for(k, 0, i)
f[i][j] = max(f[i][j], f[k][j - 1] + k * (i - k));
int len = 0, alp = 0, same = 0;
get(len, alp);
while (len) {
if (alp == 1) cout << 'a';
else if (f[len][alp - 1] >= n)
alp--, cout << char(alp - 1 + 'a'), n -= len - 1, same = 1;
else cout << char(alp - 1 + 'a'), n -= len - 1 - same, same++;
len--;
}
return 0;
}