A. Question Marks
解析:如果答案为A,B,C,D且他们的数量不大于n,则正确答案数量+1
#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2)
#define debug(x) cout << "[debug] " #x << " = " << x << '\n';
#define double long double
#define int long long
#define xiaowen ac
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e6 + 7;
const int mod =1e9+7;
multiset<int>s1,s2;
int a[N];
string s[N];
vector<int>e[N];
int vis[2*N];
int flag;
void solved() {
int n;
cin>>n;
string s;
cin>>s;
map<int,int>mp;
int ans=0;
for (int i=0;i<4*n;i++){
if (s[i]!='?'){
if (mp[s[i]]<n){
ans+=1;
mp[s[i]]+=1;
}
}
}
cout<<ans<<"\n";
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int T;
// T = 1;
cin >> T;
while (T--) {
solved();
}
return 0;
}
B. Parity and Sum
解析:
因为一个偶数加一个奇数,结果一定是一个奇数,所以替换之后肯定会比原来多一个大奇数。
因此我们可以每次用当前最大的奇数与最小的偶数进行替换,最优情况代价是偶数的数量。
但是可能会出现一个情况就是我当前最大的奇数,比当前最小的偶数要小。
所以这时候会花费次数在这上面,但是我们可以一开始用最大的奇数与最大的偶数替换。
这时候得到的奇数肯定是最大的,而且额外花费的次数只用了一次,这个情况代价是偶数数量+1。
因此我们取min(最大奇数与最小偶数进行替换的代价,偶数数量+1)
#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2)
#define debug(x) cout << "[debug] " #x << " = " << x << '\n';
#define double long double
#define int long long
#define xiaowen ac
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e6 + 7;
const int mod =1e9+7;
int a[N];
void solve() {
int n;
cin>>n;
for (int i=1;i<=n;i++){
cin>>a[i];
}
int ans=0;
priority_queue<int>j,o;
int maxxo=0,maxxj=0;
int flag=0;
for (int i=1;i<=n-1;i++){
if (a[i]%2!=a[i+1]%2){
flag=1;
}
if (a[i]%2==0){
o.push(-a[i]);
// maxxo=max(a[i],maxxo);
}else{
j.push(a[i]);
// maxxj=max(a[i],maxxj);
}
}
if (a[n]%2){
j.push(a[n]);
}else{
o.push(-a[n]);
}
int x=o.size();
int minn=1e18;
if (!flag){
cout<<"0\n";
return;
}else{
while (!o.empty()){
int ans1=-o.top();
int ans2=j.top();
int ans3=ans1+ans2;
//o.pop();
j.pop();
if (ans1<ans2){
o.pop();
}
j.push(ans3);
ans+=1;
}
}
minn=min(ans,x+1);
cout<<minn<<"\n";
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int T;
// T = 1;
cin >> T;
while (T--) {
solve();
}
return 0;
}
C. Light Switches
解析:
房间所有灯全亮的最短时间只会出现在最后一盏灯亮的时段。
那我们判断这段时间是否会有n盏灯同时亮的时刻即可。
我是用了一个map前缀和,来判断是否有全亮的时候。
#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2)
#define debug(x) cout << "[debug] " #x << " = " << x << '\n';
#define double long double
#define int long long
#define xiaowen ac
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e6 + 7;
const int mod =1e9+7;
int a[N];
void solve() {
map<int,int>mp;
int n,k;
cin>>n>>k;
int maxx=0;
for (int i=1;i<=n;i++){
cin>>a[i];
maxx=max(a[i],maxx);
}
sort(a+1,a+1+n);
for (int i=1;i<=n;i++){
int x=maxx-a[i];
int res=x%k;
if (x/k%2){
mp[(k-1)-res+maxx+1]+=1;
}else{
mp[maxx-res]+=1;
mp[(k-1)-res+maxx+1]-=1;
}
}
int ans=0;
for (auto it:mp){
if (it.first>=maxx+k){
break;
}
// cout<<it.first<<" "<<it.second<<" "<<ans<<"***\n";
ans+=it.second;
if (ans>=n){
cout<<it.first<<"\n";
return;
}
}
cout<<"-1\n";
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int T;
// T = 1;
cin >> T;
while (T--) {
solve();
}
return 0;
}
D. Med-imize
解析:
我们可以根据中位数的性质,子数组中肯定会有(n+1)/2个数字大于等于中位数。
因此我们可以选择二分答案中位数。
判断符合要求的子数组中是否有大于等于(n+1)/2个数字大于等于中位数
接下来就是如何写check里面的东西了。
因为你正常枚举剩下的,需要O(n),还得排序,外面套个二分,就得O(n2lgn2)的复杂度。
因此我们还需要发现一些性质去优化时间。
数组删去之后剩下的肯定会小于等于k,我们可以发现剩下这些位置%k,是按1,2,3…,0这样排序的。
比如4,8,8,5,4,3,1,2。此时k等于3,那么剩下的可以是1,2,它们坐标对应7,8正好mod3等于1,2。
我们可以算出剩下子数组的大小,也就是(n-1)%k+1,这样可以避免n%k=0的情况。
因此我们选择的每一个下标(i-1)%k+1必须小于等于(n-1)%k+1。
这样就像找一个递增子序列里面大于等于mid的数量最多,我们可以考虑DP。
因为我们所选择的子数组下标是按1,2,3,4…(n-1)%k+1,1,2,3,4,…,(n-1)%k+1这样循环的,所以DP i的时候可以从前一个继承,也可以继承上一轮的。
我写的是原地滚动,理解可能会不好一点
也有不是原地滚动,但原理都一样
#include <bits/stdc++.h>
using namespace std;
#pragma G++ optimize(2)
#define debug(x) cout << "[debug] " #x << " = " << x << '\n';
#define double long double
#define int long long
#define xiaowen ac
typedef unsigned long long ull;
typedef long long ll;
typedef pair<int, int> PII;
const int N = 1e6 + 7;
const int mod =1e9+7;
int a[N];
int dp[N];
int n,k;
int check(int mid) {
for (int i=0; i<=n; i++) {
dp[i]=0;
}
int ans=0;
int maxx=0;
for (int i=0; i<n; i++) {
if (i%k>(n-1)%k) {
continue;
}
if (i%k==0) {
if (a[i]>=mid){
dp[i]=1;
}
} else {
if (a[i]>=mid) {
dp[i]=dp[i-1]+1;
}else{
dp[i]=dp[i-1];
}
}
if (i>=k){
dp[i]=max(dp[i],dp[i-k]);
}
if (dp[i]>((n-1)%k+1)/2){
//cout<<"111\n";
return 1;
}
}
return 0;
}
void solve() {
cin>>n>>k;
map<int,vector<int>>mp;
for (int i=0;i<n; i++) {
cin>>a[i];
}
if (n<=k) {
sort(a,a+n);
cout<<a[(n-1)/2]<<"\n";
return;
}
for (int i=0; i<=n; i++) {
dp[i]=0;
}
int l=0,r=1e10;
while (l+1<r) {
int mid=(l+r)/2;
if (check(mid)) {
l=mid;
} else {
r=mid;
}
}
cout<<l<<"\n";
}
signed main() {
ios::sync_with_stdio(false);
cin.tie(nullptr), cout.tie(nullptr);
int T;
// T = 1;
cin >> T;
while (T--) {
solve();
}
return 0;
}