A
题意: 给一个当前分数,问距离下一个分数段还差多少分
题解: 无
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n;
cin >> n;
if(n < 100)
cout << 100 - n << endl;
else if(n < 200)
cout << 200 - n << endl;
else if(n < 300)
cout << 300 - n << endl;
else
cout << 400 - n << endl;
return 0;
}
B
题意: 把题意换种说法,有 n n n棵树,每天生长一米,初始高度为 a i a_i ai,问到第几天的时候,有 p p p棵树可以长到 t t t米。
题解: 把不足 t t t米的树存起来,但是存的时候存与 n n n米的差,也就是存 n − a i n - a_i n−ai,如果当前树已经大于 t t t米了,那么 p p p减一,如果 p p p大于0,那么将存起来的值小根堆排序,输出第 p p p个元素,否则输出 0 0 0。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n, t, p;
cin >> n >> t >> p;
vector<int> a;
for(int i = 1; i <= n; i ++)
{
int x;
cin >> x;
if(x >= t)
p --;
else
a.push_back(t - x);
}
if(p <= 0)
cout << 0 << endl;
else
{
sort(a.begin(), a.end());
cout << a[p - 1] << endl;
}
return 0;
}
C
题意: 给你一个长度为 n n n的字符串 s s s,问 s s s的所有排列中,不包含长度为 k k k的子串是回文串的数量。
题解: 用全排列函数枚举出 s s s的所有情况,然后暴力判断长度为 k k k的字符串就行了。
#include<bits/stdc++.h>
using namespace std;
int main()
{
int n, k;
cin >> n >> k;
string s;
cin >> s;
sort(s.begin(), s.end()); //先将s排个序
int ans = 0;
do
{
auto check = [&](string t) //lambda表达式,就是作为一个函数。
{
for(int i = 0, j = k - 1; i < j; i ++, j --)
if(t[i] != t[j])
return true;
return false;
};
bool is_find = true;
for(int i = 0; i + k <= s.size(); i ++)
{
string t = s.substr(i, k);
if(check(t))
continue;
is_find = false;
}
if(is_find)
ans ++;
}while(next_permutation(s.begin(), s.end())); //全排列函数
cout << ans << endl;
return 0;
}
D
题意: 一个非负的十进制整数 x x x如果是回文,则被称为回文数,例如( 363 , 12344321 , 0 363, 12344321, 0 363,12344321,0)都是回文数,问第 n n n个回文数是多少。
题解: 打表先找一下规律,发现 1 1 1位的有 10 10 10个, 2 2 2位有 9 9 9个, 3 3 3位的有 90 90 90个, 4 4 4位的有 90 90 90个 . . . ... ...以此类推,那么可以 c n t i cnt_i cnti表示,长度为 i i i的十进制数中,回文数有 c n t i cnt_i cnti个。然后将这个数字从头到尾一位位的拆分并且按照顺寻放下就可以了。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
ll n;
cin >> n;
vector<ll> cnt(40); //发现长度最大为38就够了
ll t = 90;
cnt[1] = 10, cnt[2] = 9;
int tot = 0;
for(int i = 3; i < 39; i ++)
{
cnt[i] = t;
tot ++;
if(tot == 2)
{
tot = 0;
t *= 10;
}
}
if(n <= 10)
{
cout << n - 1 << endl;
return ;
}
n --;
vector<int> ans(50);
for(int i = 1; i < 39; i ++)
{
if(n > cnt[i])
n -= cnt[i];
else
{
ll x = cnt[i] / 9;
if(n > 0)
ans[0] = ans[i - 1] = 1 + n / x;
n %= x;
for(int j = 1; j <= i / 2; j ++)
{
x /= 10;
if(n == 0 or x == 0)
break;
ans[j] = ans[i - j - 1] = n / x;
n %= x;
}
for(int j = 0; j < i; j ++)
cout << ans[j];
cout << endl;
break;
}
}
return 0;
}
题意: 有一个 n ∗ m n * m n∗m大小的岛屿,岛屿每一个位置的高度是 g i j g_{ij} gij,海水从四周淹没岛屿,水位每天增加一米的高度,问 1 1 1到 h h h天,岛屿每天剩余的面积是多少。
题解: b f s bfs bfs+前缀和。根据高度分出不同的情况,开 h h h个队列,把不同高度的岛屿区分开,先将四周高度小于 h h h的放进去,然后从小到大去枚举高度,加入一个新的点的时候,考虑当前高度和下一个点的高度取最大值,即 m a x ( k , g [ a ] [ b ] ) max(k, g[a][b]) max(k,g[a][b])。
#include<bits/stdc++.h>
using namespace std;
#define fir first
#define sec second
typedef pair<int,int> pii;
int main()
{
int n, m, h;
cin >> n >> m >> h;
vector<vector<int>> g(n + 1, vector<int>(m + 1));
//每个点的高度
vector<vector<int>> vis(n + 1, vector<int>(m + 1));
//每个点是否被遍历过
vector<int> ans(h + 1);
//前缀和数组(代表有多少个点被淹没了)
queue<pii> q[h + 1];
//h个队列,分别对应[1, h]高度的位置。
for(int i = 1; i <= n; i ++)
for(int j = 1; j <= m; j ++)
{
cin >> g[i][j];
if(g[i][j] > h) //如果当前的点大于h,那么一定不会被淹没,不用加入队列
continue;
if(i == 1 or j == 1 or i == n or j == m)
//如果当前是四周,那么就加入对应高度的队列中
{
vis[i][j] = 1;
q[g[i][j]].push({i, j});
ans[g[i][j]] ++;
//高度为g[i][j]的点数量+1,比这个高度高的点数量都要+1
}
}
array<int, 4> dx {0, 0, -1, 1};
array<int, 4> dy {-1, 1, 0, 0};
//四周遍历的方向
for(int k = 1; k <= h; k ++)
{
while(q[k].size())
{
auto t = q[k].front();
q[k].pop();
int x = t.fir, y = t.sec;
for(int i = 0; i < 4; i ++)
{
int a = x + dx[i], b = y + dy[i];
if(a > n or b > m or a < 1 or b < 1)
continue;
if(vis[a][b])
continue;
if(g[a][b] > h)
continue;
vis[a][b] = 1;
ans[max(k, g[a][b])] ++;
//考虑当前点如果是2,g[a][b]是1,如果放到g[a][b],那么会导致浪费一个点。
//如果当前是1, g[a][b]是2,在1的位置+1,那么会导致后边大小出问题
q[max(k, g[a][b])].push({a, b});
}
}
}
for(int i = 1; i <= h; i ++)
ans[i] += ans[i - 1]; //前缀和
for(int i = 1; i <= h; i ++)
cout << n * m - ans[i] << endl; //整个图-被淹没的
return 0;
}