Codeforces Round 957 (Div. 3)
A. Only Pluses
完整代码:
比较简单了
#include <iostream>
#include <algorithm>
#include <vector>using namespace std;typedef long long ll;const int N=1e5+10;void solve()
{int a,b,c;cin>>a>>b>>c;
//用5次排序也可以int cnt=5;while(cnt--){if(a<=b&&a<=c)a++;else if(b<=a&&b<=c)b++;else if(c<=a&&c<=b)c++;}cout<<a*b*c<<endl;
}int main ()
{ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);int t=1;cin>>t;while(t--)solve();return 0;
}
B - Angry Monk
完整代码:
#include <iostream>
#include <algorithm>
#include <vector>using namespace std;typedef long long ll;const int N=1e5+10;void solve()
{int n,k;cin>>n>>k;vector<int>a(k);for(int i=0;i<k;i++)cin>>a[i];sort(a.begin(),a.end());int cnt=0;for(int i=0;i<k-1;i++){if(a[i]==1)cnt++;else cnt+=2*a[i]-1;}cout<<cnt<<endl;
}int main ()
{ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);int t=1;cin>>t;while(t--)solve();return 0;
}
C. Gorilla and Permutation
解题思路:
我们可以发现他是一个固定顺序的排列,我们可以将排列中的数分为三类:
大元素:值大于等于 k 的数,它们对 f(i) 有正贡献,因此对最终结果
S 是正贡献。
小元素:值小于等于 m 的数,它们对 g(i) 有正贡献,因此对最终结果
S 是负贡献。
中元素:值在 m+1 到 k−1 之间的数,它们既不影响 f(i) 也不影响 g(i),因此对结果无影响。
为了最大化
S=∑f(i)−∑g(i),我们的策略是:
大元素尽量靠前:这样它们能在更多的前缀中被计入 f(i),使 ∑f(i) 最大化。
小元素尽量靠后:这样它们只在较少的前缀中被计入
g(i),使 ∑g(i) 最小化。
中元素放在中间:它们的顺序不影响结果,可以任意排列。
完整代码:
#include <iostream>
#include <algorithm>
#include <vector>using namespace std;typedef long long ll;const int N=1e5+10;void solve()
{int n,m,k;cin>>n>>m>>k;vector<int>a;//这里也可以直接输出,不用存到数组里面for(int i=n;i>=k;i--)a.push_back(i);for(int i=m+1;i<k;i++)a.push_back(i);for(int i=1;i<=m;i++)a.push_back(i);for(int i=0;i<n;i++)cout<<a[i]<<" ";cout<<endl;
}int main ()
{ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);int t=1;cin>>t;while(t--)solve();return 0;
}
D. Test of Love
解题思路:
贪心:
利用贪心的思想,我们尽可能多的去跳,能直接跳过去最好,不能在选择游,因为游的限制太多了。
我们先把上岸处理好,也就是在n的后面加一个浮木,表示我们已经到达岸上,这只是一个方便我们判断能过河的技巧,然后把浮木的位置标记出来,如果我在当前这个木头上,能跳到下一个木头上,直接跳,如果不能跳,我们看下一步是不是鳄鱼,不是鳄鱼,就可以游,在水里看看能不能跳,不能跳再游。
整理一下:
1.先判断能不能直接跳
2.不能跳就下水后看能不能跳
3.都不能跳就选择游
DP
DP[i]DP[i]DP[i]表示到达位置iii时还能继续游泳的米数(<0<0<0则不能到达)
为什么是判断剩余的游泳米数,因为在水里还能跳,我们到达最后一个水域时,如果能跳过去,答案就显而易见,我们能更好的判断是否能到达岸上。
分情况讨论:
1.当iii是浮木时:
我们就判断下一个落脚点在哪儿
是鳄鱼,则跳过
是浮木,则MAX(DP[i],DP[j])MAX(DP[i],DP[j])MAX(DP[i],DP[j])
是水域,则必须 dp[i] >= 1 才能跳入(因为跳入水中后要离开必须游泳,至少消耗 1 米)。dp[j]=max(dp[j],dp[i]−1)dp[j] = max(dp[j], dp[i] - 1)dp[j]=max(dp[j],dp[i]−1)
2.当前位置是水域:
只能向前游 1 米 到 j = i + 1(j ≤ n+1)。
对 j:
如果 j 是鳄鱼 ‘C’:不可达。
如果 j 是原木 ‘L’ 或岸 n+1 或水 ‘W’:
dp[j]=max(dp[j],dp[i]−1)dp[j] = max(dp[j], dp[i] - 1)dp[j]=max(dp[j],dp[i]−1)(游泳 1 米,消耗 1 米配额)
完整代码:
贪心:
#include <iostream>
#include <string>
#include <vector>using namespace std;void run() {int n, m, k;cin >> n >> m >> k;string s;cin >> s;vector<int> a;for (int i = 0; i < n; i++) {if (s[i] == 'L') {a.push_back(i);}}a.push_back(n + 1);int i = -1;int pos = 0;while (i < n - 1) {if (m >= a[pos] - i) {i = a[pos];} else {i += m;if (i > n - 1) {cout << "YES" << endl;return;}while (i < n && i < a[pos]) {if (s[i] != 'C' && k > 0) {i += 1;k -= 1;} else {cout << "NO" << endl;return;}}}pos += 1;}cout << "YES" << endl;
}int main() {int t;cin >> t;while (t--) {run();}return 0;
}
DP
#include <bits/stdc++.h>using namespace std;int main() {int t;cin >> t;while (t--) {int n, m, k; cin >> n >> m >> k;string s;cin >> s;vector<int> dp(n + 2, -1);dp[0] = k;for (int i = 1; i <= n + 1; i++) {if (i != n + 1 && s[i - 1] == 'C') continue;for (int t = 1; t <= m; t++)if (i - t >= 0 && (i - t == 0 || s[i - t - 1] == 'L'))dp[i] = max(dp[i], dp[i - t]);if (i > 1 && s[i - 2] == 'W') dp[i] = max(dp[i], dp[i - 1] - 1);}if (dp[n + 1] >= 0) cout << "YES\n";else cout << "NO\n";}
}
E. Novice’s Mistake
解题思路:
我们观察发现,n∗a−b<10E6n∗a−b < 10E6n∗a−b<10E6,也就是说这个字符串最多只有6位,使用题目中错误的解法时,b也就最多6次循环,所以我们直接暴力枚举即可
完整代码:
#include <iostream>
#include <algorithm>
#include <vector>
#include <cstring>
#include <set>
#include <string>using namespace std;typedef long long ll;void solve()
{int n;cin >> n;string s = to_string(n);int len = s.length();vector<pair<int, int>> ans;for(int a=1;a<=10000;a++){int maxb=len*a;int minb=max(1,len*a-5);for(int b=minb;b<=maxb;b++){ll x=n*a-b;ll y=0;for(int i=0;i<len*a-b;i++){y=y*10+s[i%len]-'0';if(y>1e15)break;}if(x==y&&y!=0)ans.push_back({a,b});}}cout << ans.size() << endl;for (auto &p : ans) {cout << p.first << " " << p.second << endl;}}int main() {ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);int t = 1;cin >> t;while (t--)solve();return 0;
}
F. Valuable Cards
解题思路:
想要区分好段坏段,我们只需要关注x的因数,只有x的因数才有可能参与构成乘积等于x的子集,刚好找到等于x的区间就需要分段
完整代码:
#include <iostream>
#include <vector>
#include <map>
#include <algorithm>using namespace std;typedef long long ll;void solve() {int n, x;cin >> n >> x;vector<int> a(n);for (int i = 0; i < n; i++) cin >> a[i];vector<int> factors;for (int i = 1; i * i <= x; i++) {if (x % i == 0) {factors.push_back(i);if (i != x / i) factors.push_back(x / i);}}sort(factors.begin(), factors.end());map<int, int> factor_index;for (int i = 0; i < factors.size(); i++)factor_index[factors[i]] = i;int count = 1;vector<bool> dp(factors.size(), false);dp[0] = true;for (int num : a) {if (x % num != 0) continue;vector<bool> dp_next = dp;bool found_x = false;for (int j = 0; j < factors.size(); j++) {if (!dp[j]) continue;ll product = (ll)factors[j] * num;if (product > x) continue;auto it = factor_index.find(product);if (it != factor_index.end()) {int idx = it->second;dp_next[idx] = true;if (product == x) found_x = true;}}if (found_x) {count++;dp.assign(factors.size(), false);dp[0] = true;auto it = factor_index.find(num);if (it != factor_index.end()) dp[it->second] = true;} else {dp = dp_next;}}cout << count << endl;
}int main() {ios_base::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);int t = 1;cin >> t;while (t--) solve();return 0;
}