zoukankan      html  css  js  c++  java
  • 【刷题】【二分】【三分】(2)

    神奇的check函数,

    任世界千变万化,我check永远是check

    1>land

    一棵树,求砍cut刀以后,
    cut+1棵数中,直径最大值 最小是多少

    //因为cut刀怎么砍与直径最大值有关,不好控制,
    //所以我们通过枚举最大的直径,然后去dfs砍枝
    
    //然后,让我们来见证,这个神奇的二分剪法 
    #include<cstdio>
    #include<cstdlib>
    #include<vector>
    using namespace std;
    int n,cut;
    const int N=4e5+3;
    int d[N],sz[N];
    vector <int> g[N];
    
    int mid,sum;
    int check(int nw,int f)
    {
        int l_mn=mid,r_mx=0,cnt=0; 
        
        for(int i=0;i<sz[nw];i++)
        {
            int u=g[nw][i];
            if(u==f) continue;
            
            int len=check(u,nw)+1;
            if(len>mid) sum++;
            else if(len>(mid>>1)) cnt++,l_mn=min(l_mn,len);
            else if(len>0) r_mx=max(r_mx,len);
        }
        
        if(cnt)
        {
            sum+=cnt;
            if(l_mn+r_mx<=mid)
            {
                sum--;
                return l_mn;
            }
        }
        return r_mx;
    }
    
    int main()
    {
        scanf("%d%d",&n,&cut);
        int u,v;
        for(int i=1;i<n;i++)
            scanf("%d%d",&u,&v),g[u].push_back(v),g[v].push_back(u);
        for(int i=1;i<=n;i++)
            sz[i]=g[i].size() ;
        
        if(cut+1>=n) 
            printf("0
    ");
        else
        {
            int l=0,r=n,ans=0;
            while(l<=r)
            {
                mid=(l+r)>>1;//>cut就是这个解太优了,要把解变差一点,就是把ans的范围往右边调整 
                sum=0,check(1,0); 
    if(sum>cut) l=mid+1; else ans=mid,r=mid-1;//重点注意这个地方的写法!!!! . //求的是cut刀,最小ans是多少, //但是有可能此最小ans的时候,最小砍cut-1刀, //所以写的时候,就是<=cut的时候,都更新答案,但是大于不行 } printf("%d ",ans); } return 0; }

    2>Best Cow Fences

    整理一个知识点:

    求最大子序列和

    O(n)

    单独考虑每个点,前面的最优解>0,就加上,如果<0,就不加,

    再选自己,

    如果自己加上最优解,都<0,就都别取了

    给你一个正整数序列,找出一个区间使得平均值最大,要求该区间的长度大于等于L。 

    策略:二分答案

    //小数二分,令人头大 
    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    int n,l;
    const int N=1e5+3;
    double d[N];
    double dd[N],sum[N],f[N];
    
    bool check(double mid)
    {
        memset(sum,0,sizeof(sum));
        memset(f,0,sizeof(f));
        for(int i=1;i<=n;i++) 
        {
            dd[i]=d[i]-mid;
            sum[i]=sum[i-1]+dd[i];
            f[i]=max(0.0,dd[i]+max(0.0,f[i-1]));
        }
        
        double ans=-1;
        for(int i=l;i<=n;i++)
            ans=max(ans,sum[i]-sum[i-l]+f[i-l]);
        return (ans>0);
    }
    
    int main()
    {
        scanf("%d%d",&n,&l);
        double mn=2003,mx=0;
        for(int i=1;i<=n;i++) 
        {
            scanf("%lf",&d[i]);
            mn=min(mn,d[i]),mx=max(mx,d[i]);
        }
        
        int cnt=500;
        double l=mn,r=mx;
    while(r-l>=0.00001 && --cnt)//注意,这里是二分小数型写法 { double mid=(l+r)/2; if(check(mid)) l=mid; else r=mid; } r*=10000; printf("%d ",(int)r/10) ; //不四舍五入型写法 return 0; }

    3>曲线

    就一个二次函数形状的图像,二分找答案最小,

    但因为x,y的取值是全实数,所以我二分x,y的时候,要多出来特别多的精度,

    大概长这样:r-l>=0.00000001

    然后计算复杂,加cnt算了

    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<algorithm>
    using namespace std;
    int t,n;
    const int N=1e5+3,inf=-2e9;
    int a[N],b[N],c[N];
    
    double f(double x)
    {
        double ans=inf;
        for(int i=1;i<=n;i++)
            ans=max(ans,double(x*x*a[i] +x*b[i] +c[i] ) );
        return ans;
    }
    
    int main()
    {
        scanf("%d",&t);
        while(t--)
        {
            scanf("%d",&n); 
            for(int i=1;i<=n;i++)
                scanf("%d%d%d",&a[i],&b[i],&c[i]);
            double l=0,r=1000,as=0;
            int cnt=400; 
            while(r-l>=0.00000001)//就是精度不够 
            {
                double m1=l+(r-l)/3,m2=r-(r-l)/3;
                double v1=f(m1),v2=f(m2);
                if(v1<=v2) r=m2,as=v1;
                else l=m1,as=v2;
            } 
            printf("%.4f
    ",as );
        }
        return 0;
    } 

    4>生日快乐

    一看就是二分,但是是 二分+搜索+小数处理...

    题目很好

    #include<cstdio>
    #include<cstdlib>
    #include<algorithm>
    using namespace std;
    int x,y,k;
    double s;
    
    double dfs(double m,double n,int cut)
    {
        if(cut==1)
            return (double)max(m,n)/min(m,n);
        
        double ans;
        double mx_m=s/n,mx_n=s/m;
        
        ans=dfs(mx_m,n,1);
        for(int i=2;i<cut;i++)
            ans=min(ans,max(dfs(mx_m*i,n,i) , dfs(m-mx_m*i,n,cut-i) ));
        for(int j=1;j<cut;j++)
            ans=min(ans,max(dfs(m,mx_n*j,j) , dfs(m,n-mx_n*j,cut-j) ));
        return ans;
    }
    
    int main()
    {
        
        scanf("%d%d%d",&x,&y,&k);
        s=x*y*1.0/k;
        printf("%.6lf
    ",dfs(x*1.0,y*1.0,k));
        
        return 0;
    }

    4>派

    5>皇帝的烦恼

  • 相关阅读:
    团队项目前期冲刺-5
    团队项目前期冲刺-4
    团队项目前期冲刺-3
    团队项目前期冲刺-2
    团队计划会议
    团队项目前期冲刺-1
    大道至简阅读笔记01
    软件工程第八周总结
    梦断代码阅读笔记03
    小组团队项目的NABCD分析
  • 原文地址:https://www.cnblogs.com/xwww666666/p/11609217.html
Copyright © 2011-2022 走看看