CF杂题选刷
CF1855B Longest Divisors Interval
对于任意一个区间 \(\left[ l,r \right]\),一定有 \(\forall i \in \left[ 1,r-l+1 \right]\),都 \(\exists j \in \left[ l,r \right]\),使得 \(i \mid j\)。
因为模 \(i\) 意义下的正整数每 \(i\) 个一循环,由于 \(i\) 小于区间长度,所以在这个区间内一定存在至少一个 \(0\)。
所以对于区间 \(\left[ l,r \right]\),若 \(\forall i \in \left[ l,r \right]\) 都满足 \(i \mid n\),那么对于 \(\forall i \in \left[ 1,r-l+1 \right]\) 也一定满足 \(i \mid n\)。
所以对于 \(\forall i \in \left[ 1,r-l+1 \right]\),都能在 \(\left[ l,r \right]\) 中找到 \(i\) 的倍数。
所以问题就转化为从 \(1\) 开始枚举,找到 \(r-l+1\) 合法的最大值。
CF1855B
void Work() {
cin >> n;
int ans = 1;
for(int i = 1; ; i++) {
if(n % i != 0) {
ans = i - 1;
break;
}
}
cout << ans << "\n";
}
CF1832C Contrast Value
首先考虑连续相等的一段值,他们的差分的绝对值为 \(0\),不会对序列的权值造成影响,可以直接删去。
再考虑递增和递减的连续段,对于这类连续段,我们把题目中给出的式子展开,发现中间的部分都消去了,只剩下头尾两个元素。
那么中间那些元素就可以删去,只留下最边上两个。
CF1832C
void Work() {
cin >> n;
for(int i = 1;i <= n; i++)
cin >> a[i];
int ans = n,tmp = -1;
for(int i = 1;i < n; i++) {
if(a[i] == a[i + 1])
ans --;
else if(tmp == 0 && a[i + 1] > a[i])
ans --;
else if(tmp == 1 && a[i + 1] < a[i])
ans --;
else
tmp = (a[i + 1] < a[i]);
}
cout << ans << "\n";
return ;
}
CF1853B Fibonaccharsis
看到 \(k\) 的范围十分吓人,但我们发现,斐波那契数列的第 \(28\) 项是 \(317811\),显然已经超过了 \(2 \times 10^5\) 这个范围。
但还要考虑我们这个数列不是真正的斐波那契数列,可以有第一项为 \(0\) 的情况,每一项会整体后移一位,所以当 \(k \geq 29\) 时,答案为 \(0\)。
那么我们现在只需要考虑 \(k \leq 28\) 的情况了,直接枚举前两项显然是不现实的,我们考虑换一个思路。
显然,对于这个数列,我们只要有其中两个相邻项的值,就可以递推求出每一项的值。
那我们可以枚举第 \(k-1\) 项的值,递推求出前两项的值,判断前两项是否合法(非递减且为非负整数序列)。
还有一个思路是:我们可以发现,类斐波那契数列的每一项是能够通过前两项的值表示出来的,可以直接解不定方程。
CF1853B
void Work() {
cin >> n >> k;
if(k >= 29) {
cout << "0\n";
return ;
}
f[k] = n;
for(int i = 1;i <= n; i++) {
f[k - 1] = i;
for(int j = k - 2;j >= 1; j--)
f[j] = f[j + 2] - f[j + 1];
if(f[2] >= f[1] && f[1] >= 0)
ans ++;
}
cout << ans << "\n";
return ;
}
CF794C Naming Company
首先有一个比较显然的贪心思路。
为使得最终字符串的字典序最小,奥列格每次选取自己字典序最小的字符,放在能够放置的最前面位置,伊戈尔每次选取自己字典序最大的字符,也放在能够放置的最前面位置。
但这样的贪心是有问题的,会错在第 \(6\) 个测试点。
考虑这样一种状况,奥列格剩下的字符中最小的都已经大于伊戈尔手中最大的,那么如果奥列格再往最前面放显然就是错的了。
这种状况下奥列格怎么最优操作呢?他可以把自己的字符往后放,这样伊戈尔就不得不把他小于奥列格的字符往前放。
那么在这种条件下,二者的最优策略就是把自己的字符从后往前放。
所以当奥列格仍然有小于伊戈尔的字符时,采取第一种策略,否则采取第二种策略。
具体代码可以用 deque
维护,支持取头尾元素,十分的方便。
时间复杂度 \(\operatorname{O}(n)\)。
CF794C
#include <bits/stdc++.h>
using namespace std;
int n;
string s,t;
deque<char> q1,q2;
int main() {
cin >> s >> t;
n = s.size();
sort(s.begin(),s.end());
sort(t.begin(),t.end());
reverse(t.begin(),t.end());
for(int i = 0;i < (n + 1) / 2; i++)
q1.push_back(s[i]);
for(int i = 0;i < n / 2; i++)
q2.push_back(t[i]);
string ansl = "",ansr = "";
bool flag = 0;
for(int i = 1;i <= n; i++) {
if(i % 2) {
if(!q2.empty() && q1.front() >= q2.front())
flag = 1;
if(flag) {
ansr += q1.back();
q1.pop_back();
}
else {
ansl += q1.front();
q1.pop_front();
}
}
else {
if(!q1.empty() && q1.front() >= q2.front())
flag = 1;
if(flag) {
ansr += q2.back();
q2.pop_back();
}
else {
ansl += q2.front();
q2.pop_front();
}
}
}
reverse(ansr.begin(),ansr.end());
string ans = ansl + ansr;
cout << ans;
return 0;
}