目录
A
首先转化为字符串存储,前两位必须是10。第三位到最后不能出现前导零,且转成数字之后需大于等于2。
#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
using namespace std;
using ll = long long;
void slove()
{
string str; cin >> str;
if(str.size() < 3 || (str[0] != '1' || str[1] != '0')) { cout << "NO" << endl; return; }
else
{
int a = 0;
for(int i = 2; i < str.size(); i++)
{
a *= 10;
a += str[i] - '0';
if(a == 0) { cout << "NO" << endl; return; }
}
if(a < 2) { cout << "NO" << endl; return; }
}
cout << "YES" << endl;
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t; cin >> t;
while(t--) slove();
return 0;
}
B
使用一个数组存储每个座位是否空位的情况:规定有人为1,空位为0。除了第一个人可以随便坐,后面所有人必须坐在左右两边数组值之和大于等于1的座位。(为了避免越界,简化代码,不特判边界情况,请将数组开大一点)
#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
using namespace std;
using ll = long long;
void slove()
{
int n; cin >> n;
vector<int> a(n + 10, 0);
bool flag = true;
for(int i = 1; i <= n; i++)
{
int t; cin >> t;
if(i != 1)
if(a[t + 1] + a[t - 1] == 0) flag = false;
a[t] = 1;
}
if(flag) cout << "YES" << endl;
else cout << "NO" << endl;
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t; cin >> t;
while(t--) slove();
return 0;
}
C
首先预处理数组,将相同的元素的下标通过map映射到vector中。对于任意字符串,先判断长度是否和数组长度相同,然后同样也映射到vector中。遍历两个map,判断对应的下标元素是否相同
#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<map>
using namespace std;
using ll = long long;
void slove()
{
int n; cin >> n;
vector<int> nums(n + 1, 0);
map<int, vector<int>> hn;
for(int i = 1; i <= n; i++)
{
cin >> nums[i];
hn[nums[i]].push_back(i);
}
int m; cin >> m;
while(m--)
{
map<char, vector<int> > hs;
string s; cin >> s;
if(s.size() != n) { cout << "NO" << endl; continue; }
string str = " " + s;
bool flag = true;
for(int i = 1; i < str.size(); i++)
hs[str[i]].push_back(i);
for(auto& e : hs)
{
vector<int>& b = e.second;
int c = nums[b[0]];
for(int i = 1; i < b.size(); i++)
{
if(c != nums[b[i]]) { flag = false; break; }
}
}
for(auto& e : hn)
{
vector<int>& b = e.second;
char c = str[b[0]];
for(int i = 1; i < b.size(); i++)
{
if(c != str[b[i]]) {flag = false; break; }
}
}
if(flag) cout << "YES" << endl;
else cout << "NO" << endl;
}
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t; cin >> t;
while(t--) slove();
return 0;
}
D
选择一个区间之后,就不可再选择该区间中间的区间了。每次得到的分数是该区间的和,所以我们每次都尽可能选择靠近中间的区间。那么对于先选择最靠近中间的区间,然后往两端移动,得到的分数;和从两端往中间靠依次得到的分数是相同的。对于一个区间的和,利用前缀和处理。
#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<map>
using namespace std;
using ll = long long;
void slove()
{
int n; cin >> n;
vector<int> nums(n + 1, 0);
vector<ll> pre(n + 1, 0);
for(int i = 1; i <= n; i++)
{
cin >> nums[i];
pre[i] = pre[i - 1] + nums[i];
}
string a; cin >> a;
string str = " " + a;
ll res = 0;
for(int i = 1, j = n; i < j; i++, j--)
{
while(i < j && str[i] != 'L') i++;
while(i < j && str[j] != 'R') j--;
if(str[i] == 'L' && str[j] == 'R')
res += pre[j] - pre[i - 1];
}
cout << res << endl;
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t; cin >> t;
while(t--) slove();
return 0;
}
E
尽可能将高的猩猩放在被小方格覆盖次数最多的单元格中。对于一个 k*k 的小方格,最多覆盖一个单元格 k*k 次。可以对于 n*m 的网格中的每一个单元格求出被 k*k 的小方格覆盖的次数,利用二维差分。使用大根堆存储,然后将数组降序排列,依次相乘即为答案。时间复杂度O(n*m)
#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
#include<cmath>
#include<queue>
using namespace std;
using ll = long long;
void slove()
{
int n, m, k; cin >> n >> m >> k;
int w; cin >> w;
vector<vector<int>> cnt(n + 2, vector<int>(m + 2, 0));
vector<int> a(w, 0);
for(int i = 0; i < w; i++) cin >> a[i];
sort(a.begin(), a.end(), greater<int>());
for(int i = 1; i <= n - k + 1; i++)
for(int j = 1; j <= m - k + 1; j++)
{
cnt[i][j]++;
cnt[i + k][j]--;
cnt[i][j + k]--;
cnt[i + k][j + k]++;
}
vector<vector<int>> pre(n + 1, vector<int>(m + 1, 0));
priority_queue<int, vector<int>> q;
for(int i = 1; i <= n; i++)
{
for(int j = 1; j <= m; j++)
{
pre[i][j] = pre[i - 1][j] + pre[i][j - 1] - pre[i - 1][j - 1] + cnt[i][j];
q.push(pre[i][j]);
}
}
ll res = 0;
for(int i = 0; i < w; i++)
{
res += (ll) q.top() * a[i];
q.pop();
}
cout << res << endl;
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t; cin >> t;
while(t--) slove();
return 0;
}
F
对于一个矩阵中的单元格染色,可能会造成行或列变满,从而加分。对于任意 n*m 矩阵,最多是全部染色,n*m 分。每一次加分都是行变满或者列变满导致的,可以动态规划求得任意一个矩阵,加分 [0, n*m] 的最小操作数。所以可以先预处理 n 个矩阵,val[i][j]:第 i 个矩阵分数为 j 所需的最小操作数。时间复杂度O(n*a*b)(a 和 b 为任意矩阵的长宽)
预处理好之后就可以转变为一个01背包的问题了:对于 n 个矩阵,每个矩阵选与不选,分数至少为 k ,最少操作数是多少。
集合:f[i][j]:从前 i 个矩阵中选择,分数至少为 j 的最小操作数。
对于第 i 个矩阵:
- 不选:f[i - 1][j]
- 选: f[i - 1][j - v] + val[i][v]
#include<iostream>
#include<algorithm>
#include<vector>
#include<string>
using namespace std;
using ll = long long;
void slove()
{
int n, k; cin >> n >> k;
vector<vector<int>> val(n + 1, vector<int>(k + 1, 1e9));
for (int i = 1; i <= n; i++)
{
int x, y; cin >> x >> y;
for (int a = 0; a <= x; a++)
{
for (int b = 0; b <= y && a + b <= k; b++)
{
val[i][a + b] = min(val[i][a + b], a * y + b * x - a * b);
}
}
}
vector<vector<int>> f(n + 1, vector<int>(k + 1, 1e9));
f[0][0] = 0;
for (int i = 1; i <= n; i++)
for (int j = 0; j <= k; j++)
{
f[i][j] = f[i - 1][j];
for (int v = 0; v <= j; v++)
f[i][j] = min(f[i][j], f[i - 1][j - v] + val[i][v]);
}
int res = 1e9;
for (int i = 1; i <= n; i++)
res = min(res, f[i][k]);
if (res == 1e9) res = -1;
cout << res << endl;
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int t; cin >> t;
while (t--) slove();
return 0;
}