#include<iostream>
using namespace std;
int main()
{
int sum = 0;
for (int i = 1; i <= 2020; ++i)
{
int tmp = i;
while (tmp)
{
if (tmp % 10 == 2)
{
sum++;
}
tmp /= 10;
}
}
cout << sum << endl; // 答案624
return 0;
}
2B:既约分数(填空5分_gcd)
题目描述:
题目分析:
其实就是求分子,分母 [ 1,2020 ] 中的最大公约数为一的个数
可以考虑使用STL的__gcd()函数
答案2481215
cpp复制代码
#include<iostream>
using namespace std;
int gcd(int a, int b)
{
return b ? gcd(b, a % b) : a;
}
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++;
if (gcd(i, j) == 1)
res++;
}
}
cout << res << endl; // 答案2481215
return 0;
}
3C:蛇形填数(填空10分_找规律)
题目描述:
题目解析:
这道题目可以观察,可以写代码。
观察发现每次对角线值的差是4的倍数,可以通过递推的方式计算。
答案761
cpp复制代码
`#include<iostream>
using namespace std;
int a[100][100];
int main()
{
int cnt = 1;
int x, y;
for (int i = 1;i <= 40;i++)
{
if (i % 2 == 1)
{
for (x = i, y = 1;x >= 1 && y <= i; --x, ++y)
{
a[x][y] = cnt++;
}
}
else
{
for (x = 1, y = i;x <= i && y >= 1; ++x, --y)
{
a[x][y] = cnt++;
}
}
}
cout << a[20][20]; // 答案761
return 0;
}`
4D:跑步锻炼(填空10分_模拟)
题目描述:
题目解析:这个问题简单暴力的解决方法可以直接遍历每一天,算出每一天的日期,并使用一个计数器计数。
答案8879
cpp复制代码
#include<iostream>
using namespace std;
int get_month_day[13] = { 0,31,28,31,30,31,30,31,31,30,31,30,31 };
int main()
{
int year, month, day, week = 6, sum = 0;
for (year = 2000;year <= 2020;year++)
{
if ((year % 400 == 0) || (year % 4 == 0 && year % 100 != 0))
{
get_month_day[2] = 29;
}
for (month = 1;month <= 12;month++)
{
for (day = 1;day <= get_month_day[month]; ++day)
{
if (day == 1 || week == 1)
sum += 2;
else
sum += 1;
week = (week + 1) % 7;
if (year == 2020 && month == 10 && day == 1)
{
cout << sum << endl; // 到时间就退出来, 答案8879
return 0;
}
}
}
get_month_day[2] = 28;
}
return 0;
}
#include<iostream>
#include<cstdio>
using namespace std;
int get_month_day[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
bool check(int date) // 判断是否位合法日期
{
int year = date / 10000;
int month = date % 10000 / 100;
int day = date % 100;
if (!month || month >= 13 || day == 0)
return false;
if (month != 2 && day > get_month_day[month])
return false;
if (month == 2)
{
bool leap = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
if (day > 28 + leap)
return false; // 如果二月的天数>大于原本的二月天数+(可能的闰年+1的天数)
}
return true;
}
bool checkAB(int s) // 判断AB
{
bool flag = false;
int y = s / 10000; // 得到年份
int m = (s / 100) % 100; // 得到月份(BA)
int d = s % 100; // 得到日(BA)
int k = y / 100; // AB
int n = y % 100; // AB
if (k == n && m == d) // 判断是否为ABABBABA
flag = true;
return flag;
}
int main()
{
int date;
cin >> date;
int flag = 0;
for (int i = (date / 10000) + 1; i <= 9999; i++) // 枚举四位数的年份
{ // 举例 i=1234
int left = i;
int right = i; // 构造出来的回文串,构造出来的回文串即:12344321
for (int j = 0; j < 4; ++j)
{
right = right * 10 + left % 10; // 1234*10+1234%10
left = left / 10; // 得到left的下一位
} // 因为是按顺序进行的枚举,所以先符合条件的第一个必然是顺序最小的那一个
if (check(right))
{
++flag; // 保证第一个符合的回文串只有一个输出
if (flag == 1)
cout << right << endl;
if (checkAB(right))
{
cout << right << endl;
return 0;
}
}
}
return 0;
}
解析代码(模拟)
cpp复制代码
#include <iostream>
#include <cstring>
#include <string>
#include <algorithm>
using namespace std;
int get_month_day[13] = { -1 , 31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 };//每个月的天数
bool checkLeapYear(int y) // 判断闰年
{
if (y % 400 == 0 || (y % 4 == 0 && y % 100 != 0))
return true;
return false;
}
bool checkABABBABAstyle(string s) // 判断是否为ABABBABA型
{
if (s[0] == s[2] && s[0] == s[5] && s[0] == s[7]
&& s[1] == s[3] && s[1] == s[4] && s[1] == s[6])
return true;
return false;
}
int main()
{
string S, ans1, ans2;
string s, t, year;
int y, m, d, i;
cin >> S;
year = S.substr(0, 4);
for (i = stoi(year); ans1 == "" || ans2 == ""; ++i) // i 初值为输入数据的年
{
// 找到了ans1和ans2,循环结束,有任何一个没有找到 就要继续循环寻找
s = to_string(i); // s为当前枚举的年
t = to_string(i);
reverse(t.begin(), t.end()); // 求i的逆
s += t; // 构造拼接出 s+s' 年月日
if (s <= S) // 构造出的s 小于起始日期,不计,
continue; // 考察下一年,下面的语句不执行
y = stoi(s.substr(0, 4));
m = stoi(s.substr(4, 2)); // 从回文串中获得年月日:y、m、d。
d = stoi(s.substr(6, 2));
if (checkLeapYear(y)) // 如果是闰年,2月的天数为29,
get_month_day[2] = 29;
if (m < 1 || m > 12)
continue;
if (d < 1 || d > get_month_day[m])
continue;
if (ans1 == "") // s是合法日期的回文串,记录在ans1中
ans1 = s;
if (checkABABBABAstyle(s) && ans2 == "")
ans2 = s; // s还符合ABABBABA型,记录在ans2中。
}
cout << ans1 << '\n' << ans2 << '\n';
return 0;
}
8H:子串分值和(编程题20分)
题目描述:
解析代码1(暴力_过50%)
暴力思路解析:哈希表存储字母出现的次数,查看哈希表中是否有多个字母即可
最外层循环枚举一次走的步长
第二层循环枚举左端点
第三层循环将左端点~~~左端点+步长的这一段距离 赋值
查找哈希表中是否存在元素,如果存在即 res++
memset:重新初始化哈希表
cout<<res<<endl;
时间O(N^3)
cpp复制代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
int main()
{
string s;
cin >> s;
int n = s.size();
int cnt[27] = { 0 };
int res = 0;
for (int len = 1; len <= n; ++len)//枚举长度
{
for (int i = 0; i + len <= n; ++i)//枚举左端点
{
for (int j = i; j < i + len; ++j)//将该段进行填充
{
cnt[s[j] - 'a']++;
}
for (int k = 0; k < 26; k++)//查找
{
if (cnt[k] != 0)
res++;
}
memset(cnt, 0, sizeof(cnt));//重新赋值为:0
}
}
cout << res << endl;
return 0;
}
解析代码2(小优化_过60%)
时间优化成O(N^2)
cpp复制代码
//}
#include <iostream>
#include <unordered_set>
using namespace std;
int main()
{
string s;
cin >> s;
int ans = 0;
for (int l = 0; l < s.size(); l++)
{
unordered_set<char> S;
for (int r = l; r < s.size(); r++)
{
S.insert(s[r]);
ans += S.size();
}
}
cout << ans << endl;
return 0;
}
那么往左最多能延伸到 last[s[i]] + 1,其到第 i 个字母一共有 i - last[s[i]] 个字母;
同理往右最多能延伸到 n,其到第 i 个字母一共有 n - i + 1 个字母;
二者相乘,就是该字母被不同子串所包含的总次数;
样例解释的排列就是这个思路,5 + 8 + 6 + 4 + 5 = 28
cpp复制代码
#include <iostream>
using namespace std;
typedef long long LL;
int last[200];
int main()
{
string s;
cin >> s;
int n = s.size();
s = ' ' + s;
LL ans = 0;
for (int i = 1; i <= n; i++)
{
ans += (LL)(i - last[s[i]]) * (n - i + 1);
last[s[i]] = i;
}
cout << ans << endl;
return 0;
}