CF每日4题

1500左右的做到还是有点吃力

2093E 1500 二分答案

题意:给定一个长度为 n 的数组,现在要把它切成 k 份,求每一份最小的MEX中的最大值。

  • 就是找最大值,但是这个值是所有段最小的值
  • 采用二分答案,二分这个值,check这个值是否是分成k段最小的

二分查找扫盲

因为尽量找最大值 向右查找 使用上文章中模板二

cpp 复制代码
while (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;
}
相关推荐
SsummerC27 分钟前
【leetcode100】零钱兑换Ⅱ
数据结构·python·算法·leetcode·动态规划
好易学·数据结构1 小时前
可视化图解算法:二叉树的最大深度(高度)
数据结构·算法·二叉树·最大高度·最大深度·二叉树高度·二叉树深度
程序员-King.1 小时前
day47—双指针-平方数之和(LeetCode-633)
算法·leetcode
阳洞洞1 小时前
leetcode 1035. Uncrossed Lines
算法·leetcode·动态规划·子序列问题
小鹿鹿啊2 小时前
C语言编程--15.四数之和
c语言·数据结构·算法
rigidwill6662 小时前
LeetCode hot 100—最长有效括号
数据结构·c++·算法·leetcode·职场和发展
wuqingshun3141593 小时前
蓝桥杯17. 机器人塔
c++·算法·职场和发展·蓝桥杯·深度优先
图灵科竞社资讯组4 小时前
图论基础:图存+记忆化搜索
算法·图论
chuxinweihui4 小时前
数据结构——栈与队列
c语言·开发语言·数据结构·学习·算法·链表