Dashboard - 2023 CCPC Henan Provincial Collegiate Programming Contest - Codeforces
过题难度:A H F G B K E
铜奖: 2 339
银奖: 3 318
金奖: 5 523
A:
直接模拟
cpp
// Code Start Here
int t;
cin >> t;
while(t--){
string s;
cin >> s;
set<char> seen;
bool found = false;
for (int i = 1; i < sz(s); ++i) {
bool ok = true;
seen.clear();
for (int j = 0; j < i; ++j) {
if (seen.count(s[j])) {
ok = false;
break;
}
seen.insert(s[j]);
}
if (!ok) continue;
int l = i, r = sz(s) - 1;
while (l < r) {
if (s[l] != s[r]) {
ok = false;
break;
}
++l;
--r;
}
if (ok) {
found = true;
break;
}
}
cout << (found ? "HE\n" : "NaN\n");
}
H
思路:我们发现0.5会进位,而距离0.5无穷左边就会被舍去,因此最小的方式是分出来的尽量距离0.5差一点点,最多的就是0.5
cpp
// Code Start Here
int t;
cin >> t;
while(t--){
int n , k;
cin >> n >> k;
if(k > 2 * n)cout << 0 << " " << 2 * n <<endl;
else{
int minv = (2 * n - k + 2) / 2;
int maxv = minv + k - 1;
cout << minv << " " << maxv << endl;
}
}
F
题意:
给定一个数列A从中选出 k 个数,计算:这些数的最大值-最小值,记作 max。这些数相邻差值中的最小值,记作 min。要求使max×min 最小
思路:我们发现排序后,任意 k 个数如果不连续,选中其中的最大和最小值之差一定不会比连续的更小。同时,相邻差值的最小值如果跳着选,差值可能会变大,而连续的差值是最稳定的。
对于连续的 k 个数,max=A[i+k−1]−A[i]。假设有k−1 个相邻差值,存在差分数组 diff,使得diff[j]=A[j+1]−A[j]。连续区间 [i, i+k-1] 中,相邻差值的最小值就是min=min(diff[i],diff[i+1],...,diff[i+k−2])。
因此我们可以遍历所有可能的连续 k 个数区间,求:每个区间内max×min,然后取最小值
考虑到5e5的数据规模,我们使用单调队列维护区间内差值的最小值。在O(1) 时间内取当前窗口最小值,且在移动窗口时自动维护单调性,效率是O(n)。
cpp
// Code Start Here
int n , k;
cin >> n >> k;
vector<int> a(n);
for(int i = 0;i<n;i++)cin >> a[i];
sort(all(a));
vector<int> diff(n-1);
for(int i = 0;i<n-1;i++)diff[i] = a[i+1] - a[i];
int ans = 1e18;
deque<int> dq;
for(int i = 0;i<n;i++){
if(i > 0){
while(!dq.empty() && diff[i-1] <= diff[dq.back()])dq.pop_back();
dq.push_back(i - 1);
}
if(i >= k){
if (!dq.empty() && dq.front() < i - k)dq.pop_front();
}
if(i >= k-1){
int max_v = a[i] - a[i-k+1];
int min_v = 1e9;
if(k > 1 && !dq.empty() )min_v = diff[dq.front()];
if(k == 1)min_v = 1e9;
ans = min(ans , 1LL *max_v * min_v);
}
}
cout << ans << endl;
return 0;
GBKE睡醒补