Codeforces Round 1039 (Div. 2)题解
A. Recycling Center
思路:我们可以去找到第一个小于等于c的位置,然后从这个位置向前贪心,看最多能0个硬币回收几个垃圾,然后用n-最多零元回收的就是最终答案了
#include<bits/stdc++.h>
using namespace std;
#define int long longint t;
int n,c;
int a[200005];
void solve()
{cin >> n >> c;for (int i = 1; i <= n;i++){cin >> a[i];}sort(a + 1, a + 1 + n);int pos = upper_bound(a + 1, a + 1 + n, c) - a;pos--;int flag = 1, cnt = 0;while(pos){if(a[pos]*flag<=c){cnt++;flag *= 2;}pos--;}cout << n - cnt << "\n";
}
signed main()
{cin >> t;while(t--)solve();return 0;
}
B. Deque Process
思路:每次直接从两边开始选,我们假设L是未选的左端点,R是未选的右端点,我们第一次选择L和R之间的小的那个,然后第二次去选择大的那个,然后不断去重复这个操作,就能形成一个波形图形,完美避免掉题目中的情况
为什么呢?首先我们此时的L和R假如要选择大的那个,假设我选择了L,那么后续的区间就变成了L+1和R,如果L+1<R,那么L+1也小于L,因为L<R,如果L+1>R,我们那么选择R也一定小于L,后续同理
#include<bits/stdc++.h>
using namespace std;
#define int long long
int t;
int n;
int a[200005];
void solve()
{cin >> n;for (int i = 1; i <= n;i++){cin >> a[i];}int l = 1, r = n;int flag = 0;//0表示选小的,1表示选大的while(l<=r){if(flag==0){if(a[l]<a[r]){l++;cout << "L";}else{r--;cout << "R";}flag = 1;}else{if (a[l] < a[r]){r--;cout << "R";}else{l++;cout << "L";}flag = 0;}}cout << "\n";
}
signed main()
{cin >> t;while(t--){solve();}return 0;
}
C. Leftmost Below
思路:我们发现,其实每个数都是前面的最小的数的2*minn-1的范围内才可能会出现,如果出现不符的直接输出NO
#include<bits/stdc++.h>
using namespace std;
#define int long long
int t;
int n;
int a[200005];
void solve()
{cin >> n;int minn = 1e9;int flag = 1;for (int i = 1; i <= n;i++){cin >> a[i];}minn = a[1];for (int i = 2; i <= n;i++){if(a[i]>minn*2-1){flag = 0;break;}minn = min(minn, a[i]);}if(flag==0){cout << "NO\n";return;}cout << "YES\n";
}
signed main()
{cin >> t;while(t--)solve();return 0;
}
D. Sum of LDS
思路:我们首先可以看到题目中的条件max(pi,pi+1)>pi+2,那么我们可以知道,最多只会有长度为2的单调递增,我们反过来考虑一下,假如说我的整个序列都是单调递减的,那么总贡献为
i=1 i *(n-i+1)=n*(n+1)*(n+2)/6,这个式子可以自己推一下,还是很好证明的
然后我们来考虑什么时候会影响贡献,也就是说会在pi<pi+1的时候贡献会-1,也就是说每次出现会产生i*(n-i)的一个减小的贡献,因为左端点的可选择性在1~i之间,右端点的选择在i+1~n之间,都会减去当前这个的反向贡献
#include<bits/stdc++.h>
using namespace std;
#define int long long
int t;
int n;
int a[2000005];void solve()
{cin >> n;for (int i = 1; i <= n;i++){cin >> a[i];}int ans = 0;for (int i = 1; i <= n;i++){ans += i * (n - i + 1);}for (int i = 1; i <= n - 1; i++){if (a[i] < a[i + 1]){ans -= i * (n - i);}}cout << ans << "\n";
}signed main()
{cin >> t;while(t--)solve();return 0;
}
E1. Submedians (Easy Version)
思路:这种题CF也已经出现过很多次了,都是用二分去解决的,我们只需要让大于mid的数的贡献是1,否则就是-1,然后用前缀去处理,如果说当前的左端点的贡献要是小于我们的flag标准,就要更新左端点,然后如果右端点的前缀值大于等于0,那么就说明当前这个区间就满足了中位数mid,然后更新mid的最大值和L和R左右区间即可
#include<bits/stdc++.h>
using namespace std;
#define int long long
int t;
int n, k;
int a[300005];
int L, R;
tuple<bool,int,int> check(int mid)
{vector<int> pre(n + 1, 0);for (int i = 1; i <= n;i++){pre[i] = pre[i - 1] + (a[i] >= mid ? 1 : -1);}int flag = 0, pos = 0;for (int r = k; r <= n;r++){if(pre[r]>=flag){L = pos + 1;R = r;return {true,pos+1,r};}int l = (r - k + 1);if(pre[l]<flag){flag = pre[l];pos = l;}}return {false,-1, -1};
}
void solve()
{cin >> n >> k;for (int i = 1; i <= n;i++){cin >> a[i];}int l = 1, r = n;int ans = 0;while(l<=r){int mid = (l + r) / 2;if(get<0>(check(mid))){ans = mid;L = get<1>(check(mid));R = get<2>(check(mid));l = mid + 1;}else{r = mid - 1;}}cout << ans << " " << L << " " << R << "\n";
}
signed main()
{cin >> t;while(t--){solve();}return 0;
}