1500左右的做到还是有点吃力
2093E 1500 二分答案
题意:给定一个长度为 n 的数组,现在要把它切成 k 份,求每一份最小的MEX中的最大值。
- 就是找最大值,但是这个值是所有段最小的值
- 采用二分答案,二分这个值,check这个值是否是分成k段最小的
因为尽量找最大值 向右查找 使用上文章中模板二
cppwhile (l < r) { int mid = l + r + 1 >> 1; //(l+r+1)/2 if (check(mid)) l = mid; else r = mid - 1; }
答案在l中
cpp
const int N=2e5+10;
int n,k;
int a[N];
bool check(int mx){
set<int>vis;
int cnt=0;
forr(i,1,n){
if(a[i]<mx)vis.insert(a[i]);
if(vis.size()==mx){
cnt++;
vis.clear();
}
}
return cnt>=k;//分的组数大,说明mx较小,选择右区间
}
void solve(){
cin>>n>>k;
forr(i,1,n){
cin>>a[i];
}
int l=0,r=n;
while (l<r)
{
int mid=(l+r+1)>>1;
if(check(mid)){
l=mid;
}else r=mid-1;
}
cout<<l<<endl;
}
2093D 1400 分治
- 题意:正方形格子边长 2 n 2^n 2n,从大到小按 3 1 ^1_3 31 2 4 ^4_2 24的形式填格子
- 对每个大格子分成四份进行处理(每条边进行分治) 维护每份格子的左上角坐标,区间值
cpp
const int N=60;
int tp[N+3];
void q1(int x,int y,int len,int mn,int mx){
if(len==1)return cout<<mn<<endl,void();
int rg=mx-mn+1;//方块的区间
if(x<=len/2&&y<=len/2){//1
q1(x,y,len/2,mn,mn+rg/4-1);
}
if(x>len/2&&y>len/2){//2
q1(x-len/2,y-len/2,len/2,mn+rg/4,mn+rg/2-1);
}
if(x>len/2&&y<=len/2){//3
q1(x-len/2,y,len/2,mn+rg/2,mn+rg/4*3-1);
}
if(x<=len/2&&y>len/2){//4
q1(x,y-len/2,len/2,mn+rg/4*3,mx);
}
}
void q2(int x,int y,int d,int len,int mn,int mx){
// cout<<x<<' '<<y<<' '<<mn<<' '<<mx<<endl;
if(len==1)return cout<<x<<' '<<y<<endl,void();
int rg=mx-mn+1;//不用mx/4确定区间 使用最大值最小值距离去规定区间
if(d<=mn+rg/4-1){//1
q2(x,y,d,len/2,mn,mn+rg/4-1);
}else if(d<=mn+rg/2-1){//2
q2(x+len/2,y+len/2,d,len/2,mn+rg/4,mn+rg/2-1);
}else if(d<=mn+rg/4*3-1){//3
q2(x+len/2,y,d,len/2,mn+rg/2,mn+rg/4*3-1);
}else if(d<=mx){//4
q2(x,y+len/2,d,len/2,mn+rg/4*3,mx);
}
}
void solve(){
int n,q;cin>>n>>q;
forr(i,1,q){
char c1,c2;
cin>>c1>>c2;
if(c1=='-'){
int x,y;
cin>>x>>y;
q1(x,y,tp[n],1,tp[n*2]);
}else {
int d;cin>>d;
q2(1,1,d,tp[n],1,tp[2*n]);
}
}
}
signed main()
{
ios::sync_with_stdio(false), std::cin.tie(nullptr), std::cout.tie(nullptr);
int _ ;
_ = 1;
tp[0]=1;
forr(i,1,N){
tp[i]=tp[i-1]*2;
// tp[i]=(1<<i);
cout<<tp[i]<<endl;
}
cin>>_;
while (_--)
{
solve();
}
return 0;
}
2092C 1200 思维 贪心
- 选两个数 a , b a,b a,b,一奇一偶,一个+1一个-1,最后两数仍是一奇一偶,可以重复操作直至 a + b , 0 a+b,0 a+b,0或 a + b − 1 , 1 a+b-1,1 a+b−1,1
- 奇+偶=奇 最后答案一定是个奇数,对原数列分奇偶
- 答案最优情况
- 所有偶数都放入一个奇数中
- 其他的奇数化成 a + b − 1 , 1 a+b-1,1 a+b−1,1,放到偶数中,加入那个最大的奇数
cpp
void solve(){
int n,ans=0,fg=0;
cin>>n;
vector<int>o,e;
forr(i,1,n){
int a;cin>>a;
if(a&1)o.push_back(a);
else e.push_back(a);
}
sort(o.begin(),o.end());
sort(e.begin(),e.end());
int lo=o.size(),le=e.size();
if(lo&&le){
for(auto i:e)ans+=i;
forr(i,0,lo-2){
ans+=o[i]-1;
}
ans+=o[lo-1];
}else if(!lo){
ans=e[le-1];
}else if(!le){
ans=o[lo-1];
}
cout<<ans<<endl;
}
2091D 1200 水 模拟
cpp
void solve(){
int n,m,k;cin>>n>>m>>k;
int a=(k+n-1)/n;//每行最大桌子数
int ad=max(2*a-1-m,0ll);//少的空格数
int cnt=a-ad;//段数
int ans=(a+cnt-1)/cnt;
// cout<<a<<' '<<ad<<' ';
cout<<ans<<endl;
}