CF 963
- B 模拟加贪心 偶数个数
- C 模拟+前缀和 灯能否全亮
- D 二分+DP 中位数尽可能大
- F1 模拟+镜像
题目链接
B 模拟加贪心 偶数个数
考点:贪心
思路:除了全是偶数的情况,其他的情况都需要将偶数转换为奇数。最少的操作步数是偶数个数,如果有一步操作执行之前最小的偶数都比最大的奇数大,则操作步数要加1,即最后结果是偶数个数+1.
代码1:
t = int(input())
for _ in range(t):
n = int(input())
a = list(map(int, input().split()))
s = -1
v = []
for x in a:
if x%2 == 0:
v.append(x)
elif x > s:
s = x
v.sort()
if s == -1 or v == []:
print(0)
continue
ans = len(v)
for t in v:
if t < s:
s += t
else:
ans += 1
break
print(ans)
代码2:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
#define int long long
#define x first
#define y second
typedef long long ll;
void solve(){
int n;cin>>n;
vector<int> odd,even;
for(int i=0;i<n;i++){
int x;cin>>x;
if(x%2==0) even.push_back(x);
else odd.push_back(x);
}
sort(even.begin(),even.end());
sort(odd.begin(),odd.end());
if(even.size()==n||odd.size()==n){
cout<<0<<endl;
return;
}
int mx=*max_element(odd.begin(),odd.end());
int ans=0,f=0;
for(int i=0;i<even.size();i++){
if(even[i]<mx){
mx+=even[i];
ans++;
}else{
f=(even.size()-1-i+2);
break;
}
}
if(f) ans+=f;
cout<<ans<<endl;
}
signed main(){
int T=1;
cin>>T;
while(T--){
solve();
}
return 0;
}
C 模拟+前缀和 灯能否全亮
考点:模拟,前缀和
思路:将每盏灯的每个打开时刻标记为1,关闭时刻标记为-1。当前时刻的前缀和为1即表示有一盏灯打开,为0则表示没有灯打开。最后判断是否有时刻打开灯的数量为n。
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
#define int long long
#define x first
#define y second
typedef long long ll;
void solve(){
int n,k;cin>>n>>k;
vector<int> a(n+1),s(8*k+2),c(8*k+1);
int mx=0;
for(int i=0;i<n;i++){
cin>>a[i];
mx=max(mx,a[i]);
}
int m=2*k;
for(int i=0;i<n;i++){
int t=a[i]%m,f=1;
while(t<=8*k){
if(f) c[t]++;
else c[t]--;
t+=k;
f=1-f;
}
}
for(int i=0;i<8*k;i++){
s[i+1]=s[i]+c[i];
}
for(int i=mx%m+m+1;i<=8*k;i++){
if(s[i]==n){
int t=i-1-(mx%m+m);
cout<<mx+t<<endl;
return;
}
}
cout<<-1<<endl;
}
signed main(){
int T=1;
cin>>T;
while(T--){
solve();
}
return 0;
}
D 二分+DP 中位数尽可能大
考点:二分+序列DP
思路:对于中位数,大多数情况可以考虑二分。本题的trick是删除k个连续数的技巧。
代码1:本质思路
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
#define int long long
#define x first
#define y second
typedef long long ll;
const int inf=1e9+10;
int u,v;
void solve() {
int n,k;
cin>>n>>k;
vector<int> a(n);
for(int i=0; i<n; i++) cin>>a[i];
if(k==1) {
cout<<*max_element(a.begin(),a.end())<<endl;
return;
}
if(n<=k) {
sort(a.begin(),a.end());
cout<<a[(n-1)/2]<<endl;
return;
}
u=(n-1)/k+1,v=(n-1)%k+1;//这里要注意
vector<vector<int>> b(u+1,vector<int>(v+1));
// vector<vector<int>> f(u+1,vector<int>(v+1,-inf));//不能在这里定义,不然f数组不能每次执行check函数就初始化一次
for(int i=0; i<u; i++) {
for(int j=0; j<v; j++) {
b[i][j]=a[i*k+j];
}
}
auto check=[&] (int x) {
vector<vector<int>> f(u+1,vector<int>(v+1,-inf));//不能全部初始为-1,要尽量初始化更小一点
for(int i=0; i<u; i++) {
for(int j=0; j<v; j++) {
if(i>0) f[i][j]=max(f[i][j],f[i-1][j]);
if(j==0) {
int t=(b[i][j]>=x?1:-1);
f[i][j]=max(f[i][j],t);
} else {
if(j>0) f[i][j]=max(f[i][j],f[i][j-1]+(b[i][j]>=x?1:-1));
if(i>0&&j>0) f[i][j]=max(f[i][j],f[i-1][j-1]+(b[i][j]>=x?1:-1));
}
// cout<<"----- "<<i<<" "<<j<<' '<<f[i][j]<<endl;
}
}
int ans=-1e9;
for(int i=0;i<u;i++){
ans=max(ans,f[i][v-1]);
}
// return ans>=(v+2)/2;
return ans>0;
};//逗号
int l=1,r=1e9+10;
while(l+1<r) {
int mid=l+r>>1;
if(check(mid)) l=mid;
else r=mid;
}
cout<<l<<endl;
}
signed main() {
int T=1;
cin>>T;
while(T--) {
solve();
}
return 0;
}
代码2:优化
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define x first
#define y second
typedef long long ll;
const int N=5e5+10,inf=1e9+10;
int a[N],b[N],f[N];
int n,k;
bool check(int x){
// memset(f,-0x3f,sizeof f);//一定要注意超时
for(int i=0;i<n;i++){
if(a[i]>=x) b[i]=1;
else b[i]=-1;
}
f[0]=b[0];
for(int i=1;i<n;i++){
if(i%k==0){
f[i]=max(f[i-k],b[i]);
}else{
f[i]=f[i-1]+b[i];
if(i>k){
f[i]=max(f[i],f[i-k]);
}
}
}
return f[n-1]>0;
}
void solve(){
cin>>n>>k;
for(int i=0;i<n;i++) cin>>a[i];
int l=1,r=inf;
while(l+1<r){
int mid=l+r>>1;
if(check(mid)) l=mid;
else r=mid;
}
cout<<l<<endl;
}
signed main(){
int T=1;
cin>>T;
while(T--){
solve();
}
return 0;
}
F1 模拟+镜像
考点:模拟+镜像
代码:
#include<bits/stdc++.h>
using namespace std;
const int N=5e6+10;
#define int long long
string s;
int n,k,w,h;
int tx[2*N],ty[2*N];
map<pair<int,int>,int> cnt;
void solve(){
cin>>n>>k>>w>>h>>s;
cnt.clear();
int x=0,y=0;
for(int i=0;i<n;i++){
if(s[i]=='L') x--;
if(s[i]=='R') x++;
if(s[i]=='U') y++;
if(s[i]=='D') y--;
x=(x+2*w)%(2*w);
y=(y+2*h)%(2*h);
cnt[{x,y}]++;
}
int ans=0;
for(int i=0;i<k;i++){
int vx=(-i*x%(2*w)+2*w)%(2*w);
int vy=(-i*y%(2*h)+2*h)%(2*h);
ans+=cnt[{vx,vy}];
}
cout<<ans<<endl;
}
signed main(){
int T=1;
cin>>T;
while(T--){
solve();
}
return 0;
}