Codeforces Round 957 (Div 3)(A—G题解)
Codeforces Round 957 (Div. 3)
2024-07-12 —yimg
A
签到题
代码:
#include<bits/stdc++.h>
using namespace std;
void work()
{
vector<int> a(3);
for(int i = 0; i < 3; ++i) cin >> a[i];
int t = 5;
while(t--){
sort(a.begin(), a.end());
a[0]++;
}
cout << a[0]*a[1]*a[2] << '\n';
}
int main()
{
int t;
cin >> t;
while(t--)
work();
}
B
签到题
代码:
#include<bits/stdc++.h>
using namespace std;
void work()
{
int n, k;
cin >> n >> k;
vector<int> a(k);
for(auto &i: a) cin >> i;
sort(a.begin(), a.end());
int ans = 0;
for(int i = 0; i < k - 1; ++i){
ans += a[i] - 1;
}
cout << ans + n - a[k - 1] << '\n';
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--)
work();
}
C
签到题
代码:
#include<bits/stdc++.h>
using namespace std;
void work()
{
int n, m, k;
cin >> n >> m >> k;
vector<int> a(n + 1);
int j = 1;
for(int i = n; i > m; --i, ++j){
a[j] = i;
}
for(int i = 1; i <= m; ++i, ++j){
a[j] = i;
}
for(int i = 1; i <= n; ++i)
cout << a[i] << " ";
cout << "\n";
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--)
work();
}
D
题意:
ErnKor过河,这条河有n个格子,L代表平台可以跳往[L,L + m]的任意位置,W代表水,每经过一格水要消耗一个体力,最开始有k个体力,也就是最多经过k格水,C代表鳄鱼,不能待在C所在的格子。给定n,m,k 和一个代表河流的字符串,问能否到达对岸
思路:
-
比较容易想到的是用贪心来做,如果在能跳往下一个平台,跳往下一个平台一定是最优操作,如果不能,跳满m格是最优操作,其中会判NO的情况是在水中遇到’C’或者体力不够用,复杂组O(n + k)
-
dp来解决问题也很浅显,我们记录到当前格子要消耗的最小体力,我们当前的格子可能是由前面的格子跳过来的,或者由上一个水游过来的。 鳄鱼初始为极大值后不用管,因为我们不能通过‘C’转移。复杂度为O(nm)。
代码:
贪心
#include<bits/stdc++.h>
using namespace std;
void work()
{
int n, m, k;
cin >> n >> m >> k;
string s;
cin >> s;
for(int l = -1, r = 0; r <= s.length(); ++r){
if(l == s.length()) break;
if(l + m < r){
l = l + m;
if(s[l] == 'C'){
cout << "NO\n";
return;
}
while(1){
k--;
++l;
if(s[l] == 'C' || k < 0){
cout << "NO\n";
return;
}
if(l == s.length() || s[l] == 'L'){
r = l;
break;
}
}
}
else if(r == s.length() || s[r] == 'L'){
if(l + m >= r){
l = r;
}
}
}
cout << "YES\n";
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--)
work();
}
DP
#include<bits/stdc++.h>
using namespace std;
void work()
{
int n, m, k;
cin >> n >> m >> k;
string s;
cin >> s;
s = "L" + s + "L";
vector<int> f(n + 5, 1e9 + 7);
f[0] = 0;
for(int i = 1; i <= n + 1; ++i){
for(int j = 1; j <= m; ++j){
if(i - j >= 0 && s[i - j] == 'L')
f[i] = min(f[i], f[i - j]);
}
if(s[i - 1] == 'W') f[i] = min(f[i], f[i - 1] + 1);
}
if(f[n + 1] <= k) cout << "YES\n";
else cout << "NO\n";
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--)
work();
}
E
题意:
给定n, 问有多少对符合要求的数对(a, b)满足
定义
思路:
a和b的范围都很小,直接枚举a,对于此a我们限制b的范围,
代码:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
void work()
{
int n;
cin >> n;
string chn = to_string(n);
string s;
int ln = chn.length();
for(int i = 1; i <= 10; ++i) s += chn;
vector<pair<int, int>> ans;
const int N = 1e4;
for(int a = 1; a <= N; ++a){
for(int b = max(a*ln-5, 1); b <= min(a*ln-1, min(N, a*n)); ++b){
int num = 0;
for(int i = 0; i < ln*a-b; ++i) num = num * 10 + s[i] - '0';
if(n*a-b == num) ans.push_back({a,b});
}
}
cout << ans.size() << '\n';
for(auto v : ans)
cout << v.first << " " << v.second << '\n';
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--)
work();
}
F
题意:
一个段
则称这个段为坏段,每个元素属于且只属于一个段,且分段后,所有的段都是坏段,问坏段的最小数量
思路:
贪心地分段,如果一个元素可以分到上一个段就把它放到上一个段,否则分一个新段。
实现上,可以维护使当前段乘积为x的元素(也就是因子),要避免重复可以用set,复杂度为O(nlog(D(x)))
代码:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
void work()
{
int n, x;
cin >> n >> x;
vector<int> a(n + 1);
for(int i = 1; i <= n; ++i) cin >> a[i];
set<int> s;
vector<int> tmp;
int ans = 1;
s.insert(x);
for(int i = 1; i <= n; ++i){
if(a[i] == 1) continue;
tmp.clear();
for(auto el : s) {
if(el%a[i] == 0)
tmp.push_back(el/a[i]);
}
for(auto el : tmp) s.insert(el);
if(s.find(1) != s.end()){
ans++;
s.clear();
s.insert(x);
s.insert(x/a[i]);
}
}
cout << ans << '\n';
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while(t--)
work();
}
G
题意:
求
a为长度为n的数组{1,2,3,…, n}
思路:
当我们选k个数为子集时:
- 当
时,MEX值固定为 ,子集有 种 - 当
时,MEX值不固定,但是我们可以枚举MEX值,令MEX值为m,我们要算出m-1个数有多少种选法- 选比m小的数要从
中选 个, 有 种 - 选比m大的数要从
中选 个, 有 种
- 选比m小的数要从
复杂度为
实现上,求组合数时要用到乘法逆元,预处理好即可
代码:
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 5000;
const int mod = 1e9 + 7;
ll fac[N + 5], inv[N + 5];
void init()
{
fac[0] = fac[1] = 1;
for(int i = 1; i <= N; ++i)
fac[i] = fac[i - 1] * i % mod;
auto qpow = [&](ll base, ll p){
ll res = 1;
while(p){
if(p&1) res *= base, res %= mod;
base *= base; base %= mod;
p >>= 1;
}
return res;
};
inv[N] = qpow(fac[N], mod - 2);
for(int i = N - 1; i >= 0; --i)
inv[i] = inv[i + 1] * (i + 1) % mod;
}
ll C(int a, int b){
if(a < 0 || b < 0 || a - b < 0) return 0;
return fac[a] * inv[b] % mod * inv[a-b] % mod;
}
void work()
{
int n;
cin >> n;
ll ans = 1;
for(int k = 1; k <= n; ++k){
if(2*k+1 > n){
ans += (2*k+1) * C(n, k) % mod;
ans %= mod;
continue;
}
for(int m = k + 1; m <= 2 * k + 1; ++m){
ans += m * C(m-1, m-1-k) % mod * C(n-m, 2*k+1-m) % mod;
ans %= mod;
}
}
cout << ans << '\n';
}
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
init();
while(t--)
work();
}
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步