Codeforces Round 1039 (Div. 2) 1 ~ D
今天这场有点狗运,C和D带点guess成分
但这些都得益于超✌的指导,让我茅塞顿开
(后面因为手贱重复提交罚时暴涨,我是傻逼,就当是暂避锋芒吧)

感觉这场像AI一样,搁编译器里推了可长时间(
不过也是因为之前总是犯错,还没想明白就下手写代码,白白浪费罚时
也算是一种强制自己的方法
A
/*====================My_Solution====================//
每次销毁垃圾都会导致剩下的*2
我们要对每个垃圾的“次数”进行排序
然后按次数从小到大去选择
//====================My_Solution====================*/
void solve () {
i64 n, c;
std::cin >> n >> c;
std::vector<i64> a(n + 1), b;
std::set<int> st;
for (int i = 1; i <= n; i++) {
std::cin >> a[i];
if (a[i] <= c) {
b.push_back( std::__lg(c / a[i]) );
}
}
std::sort(b.begin(), b.end());
int cnt = 0;
for (auto it : b) {
if (cnt <= it) {
cnt++;
}
}
std::cout << n - cnt << '\n';
}
B
/*====================My_Solution====================//
从双端队列中取数,使得构成的新数组中
每一次都是符合要求的,即没有连续五个递增或递减的子序列
如果原序列有序,那么我们可以轻易获得
如果是乱序,先取大的,再取小的
循环往复,即可获取答案
//====================My_Solution====================*/
void solve () {
int n;
std::cin >> n;
std::deque<int> p;
std::vector<int> q;
std::string ans = "";
for (int i = 1; i <= n; i++) {
int x;
std::cin >> x;
p.push_back(x);
}
int cnt = 1;
while (p.size()) {
if (cnt % 2 == 1) {
int x = p.front();
int y = p.back();
q.push_back(x > y ? x : y);
ans += x > y ? "L" : "R";
x > y ? p.pop_front() : p.pop_back();
} else {
int x = p.front();
int y = p.back();
q.push_back(x < y ? x : y);
ans += x < y ? "L" : "R";
x < y ? p.pop_front() : p.pop_back();
}
cnt++;
}
std::cout << ans << '\n';
}
C
/*====================My_Solution====================//
把全0数组变为目标数组
操作方式是任意选一个数x(不小于数组的最小值)
然后找到第一个a[i] < x,让a[i] += x
以上视为一次操作
先递增后递减的数组就是可以的吗?
0 0 0
40 0 0
40 20 0
40 60 0
40 60 20
40 60
也就是说,单纯递增也不一定满足要求
如果某个数字大于等于数组最小值的两倍了,那就不可以了
非递增的序列,显然是可以构造出来的
我们的问题,仅在于是否能构造前端递增的序列
4 5 6可以吗
0 0 0
4 0 0
4 1 0
4 5 0
4 5 2
4 5 6
4 5 6 3
4 5 6 7
4 5 6 7 4
我们可以看到,构造到8就不可以了
也就是说,一段连续递增序列中不能有任意一个数字>= 2 * min(递增)
不对,不是一定只能构造出先递增后递减的序列的
5 2 2 3
0 0 0 0
5 0 0 0
5 2 0 0
5 2 2 0
5 2 2 1
5 2 2 3
我们应当用f[i]表示第i位能构造出的最大数字
则f[i] = 2 * min(1 ~ i-1) - 1
//====================My_Solution====================*/
void solve () {
int n;
std::cin >> n;
std::vector<i64> a(n + 1);
std::vector<i64> premin(n + 1, INF);
std::vector<i64> f(n + 1);
for (int i = 1; i <= n; i++) {
std::cin >> a[i];
premin[i] = std::min(premin[i - 1], a[i]);
}
f[1] = a[1];
for (int i = 2; i <= n; i++) {
f[i] = 2 * premin[i - 1] - 1;
if (a[i] > f[i]) {
std::cout << "NO\n";
return;
}
}
std::cout << "YES\n";
}
D
/*====================My_Solution====================//
给定一个排列,一定满足max(p[i], p[i + 1]) > p[i + 2]
然后需要求所有[l, r]区间的最长递减子序列的长度之和??
这个数据范围,O(n)或者O(logn)
感觉O(logn)可以排除了,乱序的排列用不了二分,也没有二分答案
我们只能从排列的性质入手,这个性质还是很有意思的
也就是说,只要长度>= 3,最长递减子序列长度至少为2
能不能考虑O(n)的dp呢
最长递减子序列用dp是O(n ^ 2)的复杂度,能不能递推出来?
f[i]表示第i位多出来的答案数,对于f[i]和f[i - 1],
增加了[1, i] --> [i, i]总共i个区间
观察1st样例
1 2+1 3+2+1 == 10
1 3 6
观察2nd样例
1 2+1 3+2+1 3+2+1+1 == 17
+2 +3
1 3 6 7
观察3rd样例
1 2+1 2+1+1 3+2+2+1 3+2+2+1+1 4+3+3+2+2+1
+2 +2+2 +2+2+2
1 3 4 8 9 15
最终答案就是:
if a[i] < a[i - 1] f[i] = f[i - 1] + i
if a[i] > a[i - 1] f[i] = f[i - 1] + 1
//====================My_Solution====================*/
void solve () {
int n;
std::cin >> n;
std::vector<int> a(n + 1);
std::vector<i64> f(n + 1);
for (int i = 1; i <= n; i++) {
std::cin >> a[i];
}
i64 ans = 1;
f[1] = 1;
for (int i = 2; i <= n; i++) {
if (a[i] > a[i - 1]) {
f[i] = f[i - 1] + 1;
} else {
f[i] = f[i - 1] + i;
}
ans += f[i];
}
std::cout << ans << '\n';
}

浙公网安备 33010602011771号