A. Question Marks(贪心)
题意:给了4n个问题,每个问题有四个选项ABCD,每个答案有n个问题,如果他不会他就写问号,求最多能答对几题
分析:每次加上选项的次数与n的最小值即可。
代码:
#include<bits/stdc++.h> using namespace std; typedef long long ll; void sol(){ ll n;cin>>n; string s;cin>>s; map<char,ll>mp; for(int i=0;i<4*n;i++){ mp[s[i]]++; } ll ans=0; for(auto &x:mp){ if(x.first!='?') ans+=min(x.second,n); } cout<<ans<<endl; } int main(){ int t;cin>>t; while(t--)sol(); return 0; }
B. Parity and Sum(构造)
题意:给定一个数组a,任选一对牵引i,j,使得ai和aj具有不同的奇偶性,如果ai<aj,ai=ai+aj,否则aj=ai+aj。求使数组中所有元素具有相同奇偶性的最少操作数。
分析:算出最大奇数x,每次比他小的偶数每次更新x,如果x比最大的数小,需要再将x再加上最大的数。
代码:
#include<bits/stdc++.h> using namespace std; typedef unsigned long long ll; const int N=2e5+10; ll a[N]; void sol(){ int n;cin>>n; int ji=0,ou=0; ll x=0,sum=0; for(int i=1;i<=n;i++){ cin>>a[i]; if(a[i]%2!=0){ ji++; x=max(x,a[i]); } else ou++; } sort(a+1,a+1+n); if(ji==0||ou==0){ cout<<0<<endl; return; } else{ int i=1; while(a[i]<=x&&i<=n){ if(a[i]%2==0){ x+=a[i]; }else{ i++; continue; } i++; } if(x<a[n])cout<<ou+1<<endl; else cout<<ou<<endl; } } int main(){ int t; cin>>t; while(t--)sol(); return 0; }
C. Light Switches(数学)
题意:房间的灯起初都是关闭,安装芯片后,它先开灯k分钟,再关灯k分钟,重复,最早什么时候这些灯全部打开
分析:由于灯是周期性,可以对2k取模,得到余数b,只要余数最大差值小于k即可,此时就知道每个点的开始和结束(结束就是开始加k),然后求出所有交点的最小值加上k的倍数大于等于a数组的最大值即可。特殊:样例7余数是01289,可以将0变成10,1变成11,2变成12,这样差值就不会大于k了。
代码:
#include<bits/stdc++.h> using namespace std; typedef unsigned long long ll; const int N=2e5+10; ll a[N],b[N]; void sol(){ int n,k;cin>>n>>k; for(int i=1;i<=n;i++)cin>>a[i]; sort(a+1,a+n+1); ll mi=0x3f3f3f,ma=0; ll c=0;//为了后面操作增几倍2k准备 for(int i=1;i<=n;i++){ b[i]=a[i]%(2*k); c=max(a[i]/(2*k),c); } sort(b+1,b+n+1); for(int i=1;i<=n;i++){ if(b[i]+2*k-b[n]<=b[n]-b[i]){ b[i]+=2*k; } ma=max(ma,b[i]); mi=min(mi,b[i]); } int l=ma,r=mi+k-1; if(ma-mi>=k||(l>r)){ cout<<"-1"<<endl; return; } ll ans=min(l,r); if(ans>=a[n]){ cout<<ans<<endl; return; } ll sum=0; while(sum<a[n]){//只要让答案不小于an即可 sum=ans+(c-1)*(k*2); c++; } cout<<sum<<endl; } int main(){ int t; cin>>t; while(t--)sol(); return 0; }
D. Med-imize(二分+dp)
题意:给定n和k以及数组a,任意选长度为k的子数组删掉,如果数组的长度还是大于k必须重复操作。求剩余元素最大中值为多少
分析:先算出剩余元素有sz个,用二分找到符合条件的最大值。例如k=3,数组下标总是呈现012012012,删除任意三个数字呈现012012,一直呈现周期性,这时候用dp记录大于x(我们要找的值)的个数,如果有一半的数字大于x则返回true
代码:
#include <bits/stdc++.h> using namespace std; void solve(){ int n,k;cin>>n>>k; vector<int>a(n); for(int i=0;i<n;i++)cin>>a[i]; int sz=n%k; if(!sz)sz+=k; auto check=[&](int x){ vector<int>dp(sz,0);//存储的是>=x的个数 for(int i=0;i<n;i++){ int j=i%k; if(j>=sz)continue; if(!j)dp[j]=max(dp[j],(int)(a[i]>=x)); else dp[j]=max(dp[j],dp[j-1]+(a[i]>=x)); } return 2*dp[sz-1]>sz; }; int l=1,r=1e9; while(l<=r){ int mid=l+r>>1; if(check(mid))l=mid+1; else r=mid-1; } cout<<r<<endl; } int main(void){ cin.tie(0)->sync_with_stdio(0); int t;cin>>t; while(t--) solve(); }