A
直接统计计算即可。
#include<bits/stdc++.h> using namespace std; using ll=long long; const int MAXN=2e5+10; void solve() { int n; cin>>n; string s; cin>>s; int a,b,c,d; a=b=c=d=0; for(int i=0;i<s.size();i++) { if(s[i]=='A')a++; else if(s[i]=='B')b++; else if(s[i]=='C')c++; else if(s[i]=='D')d++; } int ans=0; ans=min(a,n)+min(b,n)+min(c,n)+min(d,n); cout<<ans<<"\n"; } int main() { int t=1; cin>>t; while(t--) solve(); return 0; }
|
B
不难发现,最后所有的数肯定都是奇数(如果是偶数,那么一定会留下一个数是奇数)。所以最基础的情况就是将所有的偶数变为奇数。
但是需要考虑,如果当前最大的奇数比当前要处理的偶数小,那么得进行额外的一次处理,可以在这个模拟的过程中动态更新最大的奇数。一开始写的很赘余,这是比赛后修改过的。
#include<bits/stdc++.h> using namespace std; using ll=long long; const int MAXN=2e5+10; void solve() { int n; cin>>n; std::vector<ll> v(n,0); bool ok=true; int odd=0,even=0; ll odd_maxn=0; for(int i=0;i<n;i++) { cin>>v[i]; if(v[i]&1) odd++,odd_maxn=max(odd_maxn,v[i]); else even++; } if(odd && even) ok=false; if(ok) { cout<<0<<"\n"; return; } else { ll ans=even; sort(v.begin(),v.end()); for(int i=0;i<n;i++) { if(v[i]&1) continue; if(odd_maxn<v[i]) { ans++; break; } odd_maxn=max(odd_maxn,odd_maxn+v[i]); } cout<<ans<<"\n"; } } int main() { int t=1; cin>>t; while(t--) solve(); return 0; }
|
C
要求最早的所有灯都亮的时刻。不难想到要从最后一个开始亮的灯往后找。
可以发现循环的周期\(T=2k\),所以我们可以将所有的灯进行整数个周期的时间移动,保证在最后亮的灯的时间附近(尽可能地靠近,可能需要特殊的处理),这样可以尽可能让所有灯在一个时间点附近亮。
我们再将所有的时间排个序,只要最大的和最小的时间差不超过\(k\)即可。输出最大的时刻。否则输出\(-1\)(因为是所有灯都集中亮最近的时刻了)。
#include<bits/stdc++.h> using namespace std; using ll=long long; const int MAXN=2e5+10; void solve() { ll n,k; cin>>n>>k; std::vector<ll> v(n,0); ll maxn=0; for(int i=0;i<n;i++) cin>>v[i], maxn=max(maxn,v[i]); ll t=2*k; for(int i=0;i<n;i++) { v[i]+=(maxn-v[i])/t*t; if(maxn-v[i]>=k) v[i]+=t; } sort(v.begin(),v.end()); bool ok=false; if(v[n-1]-v[0]+1<=k) ok=true; if(ok) { cout<<v[n-1]<<"\n"; } else cout<<-1<<"\n"; } int main() { int t=1; cin>>t; while(t--) solve(); return 0; }
|
D
分析数据范围,只能使用\(O(n)\)或者\(O(nlogn)\)的方法。考虑如何在一个数组中找到他的中位数\(x\),我们采取二分的方法。二分查找这个中位数。可以发现,到时候大于或者等于中位数的个数应该是\(\frac{k+1}{2}\)。我们可以进行预处理:大于\(x\)的数,记录其贡献为\(1\),其余为\(-1\),我们只需要选择其中的最多\(k\)个数作为一个子数组,其中大于\(x\)的个数大于\(\frac{k+1}{2}\)即可。这个可以用\(dp\)进行处理。(对应的贡献和就是大于0)
我们使用\(dp_i\)表示:到第\(i+1\)个数时,可以获得的贡献,具体的状态转移看代码。
比较折磨的一点就是原来的二分又出错了,使用jiangly大佬的写法。
#include<bits/stdc++.h> using namespace std; using ll=long long; void solve() { ll n,k; cin>>n>>k; std::vector<ll> v(n,0); for(auto &t: v) cin>>t;
auto check=[&](ll x)->bool { std::vector<ll> f(n,0); std::vector<ll> dp(n,0); for(int i=0;i<n;i++) { if(v[i]>=x) f[i]=1; else f[i]=-1; }
dp[0]=f[0]; for(int i=1;i<n;i++) { if(i%k==0) dp[i]=f[i]; else dp[i]=dp[i-1]+f[i]; if(i>=k) dp[i]=max(dp[i],dp[i-k]); } return dp[n-1]>0; };
ll l=0,r=1e9; while(l<r) { ll mid=(l+r+1)>>1; if(check(mid)) l=mid; else r=mid-1; } cout<<l<<"\n"; } int main() { int t=1; cin>>t; while(t--) solve(); return 0; }
|