HNUCM—第14届蓝桥杯C/C++组选拔赛
A
暴力是不行的,别问我怎么知道的,OI赛制一来先暴力,WA了再说
观察一下,其实这是一个动态规划,如果我们知道n位数回文数的个数,那么我们可以知道n+2位数回文串的个数,但是我们要注意如果我们设dp[n]为n位数为n位回文数的个数时,dp[n+2]!=9*dp[n],因为当n位数被围在中间时,边界上的两位数是可以为0的,所以我们的dp[n]代表边界可以包含0时dp[n]的个数,最后我们的方程就是dp[n+2]=10 * dp[n],那么我们的结果就是dp[n]-边界为0的情况,也就是dp[n]-dp[n-2]
#include<iostream>
#include<string>
using namespace std;
long long dp[100] = { 0,10,10 };
int main()
{
string s;
int n;
cin >> n;
for (int i = 3; i <= n; i++)
{
dp[i] = dp[i - 2] * 10;
}
if (n == 2)
cout << 9 << endl;
else
cout << dp[n]-dp[n-2] << endl;
return 0;
}
B
水题,模拟就行
但是如果不用string的话要注意处理一下回车的问题
#include<iostream>
#include<string>
using namespace std;
int main()
{
int n, m,a=0,b=0;
char c;
cin >> n >> m;
string s;
for (int i = 0; i < n; i++)
{
cin >> s;
for (int i = 0; i < m; i++)
if (s[i] == 'M')
a++;
else
b++;
}
cout << a << " " << b << endl;
return 0;
}
C
最难的一个题了吧,第一眼看成了数学,但是想了想应该是搜索,这题和letcode的一些搜索题风格很像,判重比较麻烦,不要使用浮点直接判,使用to_string来判重,注意为了方便判重我们需要先给数组排序,然后第二个相同的元素不需要进入递归,一定程度达到达到剪枝和判重的效果
接着就是和为1,我们可以将其分成分子,分母,每次选的数与当前选的分母求出最小公倍数组成新的分母,再求出分子,继续搜索具体细节自己写一遍就明白了。
#include<iostream>
#include<map>
#include<algorithm>
#include<string>
using namespace std;
int a[110];
int ans, n;
map<string, bool>mp;
int gcd(int x, int y) {
return y == 0 ? x : gcd(y, x % y);
}
int lcm(int x, int y) {
return x / gcd(x, y)*y;
}
void dfs(int fz, int fm, string s, int pos) {
if (fz == fm && fz) {
if (!mp[s])
ans++;
mp[s] = true;
return;
}
if (pos > n)return;
if (fz == 0)dfs(1, a[pos], s + to_string(a[pos]), pos + 1);
else {
int m = lcm(a[pos], fm);
int z = (m / a[pos]) + (m / fm) * fz;
int g = gcd(m, z);
dfs(z / g, m / g, s + to_string(a[pos]), pos + 1);
}
dfs(fz, fm, s, pos + 1);
}
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
sort(a + 1, a + 1 + n);
dfs(0, 0, "", 1);
if (ans)
printf("%d\n", ans);
else
printf("No solution!\n");
return 0;
}
D
人比较懒,能用map不用其他。
记录最大次数,然后在map中寻找和最大次数相等的元素,因为map中的键值是按照从小到大排序的,所以用迭代器遍历时也是由小到大输出的
#include<iostream>
#include<string>
#include<map>
#include<algorithm>
using namespace std;
const int maxn = 1e6 + 10;
long long nums[maxn];
int main()
{
long long n, x;
int ans = 0;
cin >> n;
map<long long , int>mp;
for (int i = 0; i < n; i++)
{
scanf("%lld", &x);
int y=(++mp[x]);
ans = max(ans, y);
}
for (auto it=mp.begin();it!=mp.end();it++)
{
if (it->second == ans)
printf("%lld ", it->first);
}
return 0;
}
E
应该是最水的一个题了
#include<iostream>
using namespace std;
int main()
{
int n;
int a = 0, b = 0;
cin >> n;
int x;
for (int i = 0; i < n; i++)
{
cin >> x;
a += x >= 80;
b += x <= 20;
}
cout << a << " " << b << endl;
return 0;
}
F
从前往后依次出现“ILOVEX”,出现一次完整的记录一次,原因自行领悟
#include<iostream>
#include<string>
#include<unordered_map>
using namespace std;
int main()
{
string s;
string s1 = "ILOVEX";
while (cin >> s)
{
int cnt = 0, ans = 0;
for (char c : s)
{
if (c == s1[cnt])
cnt++;
if (cnt == 6)
cnt = 0, ans++;
}
cout << ans << endl;
}
return 0;
}
G
栈存储当前的牌堆,用map存储表示是否当前牌堆中是否存在和要加入的牌相等的,如果存在,一直出栈,直到遇到相等的牌,出栈时注意每个出去的牌需要标记为已经在牌堆不存在了
#include<iostream>
#include<string>
#include<unordered_map>
#include<stack>
using namespace std;
int main()
{
unordered_map<int, bool>mp;
stack<int>st;
int n,x;
int ans = 0, num = 0;
cin >> n;
for (int i = 0; i < n; i++)
{
cin >> x;
if (mp.find(x) == mp.end() || mp[x] == false)
mp[x] = true, st.push(x);
else
{
num++;
while (st.top() != x)
{
num++;
mp[st.top()] = false;
st.pop();
}
mp[x] = false;
num++;
st.pop();
ans = max(num, ans);
num = 0;
}
}
cout << ans << endl;
return 0;
}
H
判断正方形方法:三个条件同时满足(1:四条边相等,2:边不为0,3:有一个直角)
判断矩形的话就是:条件1变为有2条对边相等
思路很清楚,建议自己写一遍,就不给代码了,当然判断矩形方法还有很多
I
当时脑袋一抽看到优先级就想成了拓扑排序,实际就是一个搜索,建立有向图,边的方向为年龄小的指向年龄大的,看k可以到达哪些点
#include<iostream>
#include<algorithm>
#include<queue>
using namespace std;
bool graph[110][110] = { false };
bool vis[110] = { false };
int ans = 0;
int n, m, k, u, v;
void dfs(int start)
{
for (int i = 1; i <= n; i++)
{
if (graph[start][i] && !vis[i])
{
vis[i] = true;
ans++;
dfs(i);
}
}
}
int main()
{
cin >> n >> m >> k;
for (int i = 0; i < m; i++)
{
cin >> u >> v;
graph[v][u] = true;
}
dfs(k);
cout << ans << endl;
return 0;
}
J
这题更是让我怀疑自己是不是有点毛病,二进制转换十进制写反了,末尾写成首位了,最后还是队友帮忙检查才知道
数据范围很小,基本上每种求素数方法都可以过,但是i*i<=num还是有必要的,不然1e9应该也过不了
这里使用了筛法预处理了一下1到1000内的素数
#include<iostream>
using namespace std;
bool prime[1001];
void init()
{
prime[0] = true;
prime[1] = true;
for (int i = 2; i*i <= 1000; i++)
if (!prime[i])
for (int j = i * i; j <=1000; j += i)
prime[j] = true;
}
bool check(int x)
{
long long num = 0;
int a[11] = { 0 }, len = 0;
while (x)
{
a[len++] = x&1;
x >>= 1;
}
for (int i = len - 1; i >= 0; i--)
num = num * 10 + a[i];
for (int i = 2; i * i <= num; i++)
if (num % i == 0)
return false;
return true;
}
int main()
{
int m, n;
cin >> m >> n;
init();
int ans = 0;
for (int i = m; i <= n; i++)
if (!prime[i] && check(i))
ans++;
cout << ans << endl;
return 0;
}