zoukankan      html  css  js  c++  java
  • hihocoder [Offer收割]编程练习赛14

    A.小Hi和小Ho的礼物

    谜之第1题,明明是第1题AC率比C还要低。题目是求在n个不同重量袋子选4袋,2袋给A,2袋给B,使2人获得重量相同,求问方案数。

    我也是一脸懵b。。。o(n2)暴力枚举发现把第i行列和第j行列去掉,再求剩下的a[i]+a[j]数就是解

    用容斥,要把(i,i)(i,j)(j,i)(j,j)加回来,想o(n3),结果tle

    结果发现求结果时只求a[i]+a[j]个数就行了,只需改变跟a[i]+a[j]有关的计数就可以了。

    还要有一个计数器,储存每个数字分别有多少个

    然后直接计数与a[i]+a[j]相关数据

    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #include<queue>
    #include<stack>
    #include<math.h>
    #include<vector>
    #include<map>
    #include<set>
    #include<stdlib.h>
    #include<cmath>
    #include<string>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    typedef long long ll;
    
    int h[2000010];
    int a[1010];
    int c[1000010];
    int main()
    {
        int i,n,j,k;
        memset(h,0,sizeof(h));
        memset(c,0,sizeof(c));
        scanf("%d",&n);
        for(i=0;i<n;i++)
        {
            scanf("%d",a+i);
            c[a[i]]++;
        }
        for(i=0;i<n;i++)
        {
            for(j=0;j<n;j++)
            {
                h[a[i]+a[j]]++;
            }
        }
        ll ans=0;
        for(i=0;i<n-1;i++)
        {
            for(j=i+1;j<n;j++)
            {
                if((a[i]+a[j])%2==0)
                    h[a[i]+a[j]]-=c[(a[i]+a[j])/2];
                h[a[i]+a[j]]-=c[a[j]]*2;
                h[a[i]+a[j]]-=c[a[i]]*2;
                h[a[i]+a[j]]+=2;
                h[a[i]+a[i]]+=2;
                h[a[j]+a[j]]+=2;
                ans+=h[a[i]+a[j]];
                if((a[i]+a[j])%2==0)
                    h[a[i]+a[j]]+=c[(a[i]+a[j])/2];
                h[a[i]+a[j]]+=c[a[j]]*2;
                h[a[i]+a[j]]+=c[a[i]]*2;
                h[a[i]+a[j]]-=2;
                h[a[i]+a[i]]-=2;
                h[a[j]+a[j]]-=2;
            }
        }
        printf("%lld
    ",ans/2);
        return 0;
    }
    View Code

    B.投掷硬币

    意外地很简单。dp一波,dp[n,i]表示银币投n次正好i次向上的概率,然后

    dp(n,i)=dp(n-1,i)*(1-p(n))+dp(n-1,i-1)*p(n),解决

    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #include<queue>
    #include<stack>
    #include<math.h>
    #include<vector>
    #include<map>
    #include<set>
    #include<stdlib.h>
    #include<cmath>
    #include<string>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    typedef long long ll;
    
    double p[1010];
    double dp[2][1010];
    int main()
    {
        int i,j,m,n;
        scanf("%d%d",&n,&m);
        for(i=0;i<n;i++)
            scanf("%lf",p+i);
        memset(dp,0,sizeof(dp));
        int old=1,now=0;
        dp[0][0]=1;
        for(i=0;i<n;i++)
        {
            old^=1,now^=1;
            memset(dp[now],0,sizeof(dp[now]));
            for(j=0;j<i+1;j++)
            {
                dp[now][j]+=dp[old][j]*(1-p[i]);
                dp[now][j+1]+=dp[old][j]*p[i];
            }
        }
        printf("%lf
    ",dp[now][m]);
        return 0;
    }
    View Code

    C.可疑的记录

    题目大意就是求去除某边使n个边的有向无环图变成n-1条边的有向无环图的边编号集合

    这里不是判个圈就解决的,不仅要让有向树只有1个0入度点(编号还必须是1),并且所有0出度点只有1个入度

    所以判完圈后,还要把标记在圈上的边分别操作,并判断0入度点数和0入度点是不是1号

    #include<stdio.h>
    #include<string.h>
    #include<stdlib.h>
    #include<queue>
    #include<stack>
    #include<math.h>
    #include<vector>
    #include<map>
    #include<set>
    #include<stdlib.h>
    #include<cmath>
    #include<string>
    #include<algorithm>
    #include<iostream>
    using namespace std;
    
    const int N =100010;
    
    int head[2][N],cnt[2]={0,0};
    int to[2][N<<1],next1[2][N<<1];
    bool isCircle[N<<1];
    bool vis[N];
    bool ans[N];
    
    void addedge(int u,int v,int i)
    {
        to[i][cnt[i]]=v;
        next1[i][cnt[i]]=head[i][u];
        head[i][u]=cnt[i]++;
    }
    
    int dfs(int u,int eno)
    {
        vis[u]=true;
        int cn=-1;
        for(int i=head[1][u];i!=-1;i=next1[1][i])
        {
            if(i == (eno^1))
                continue;
            int v=to[1][i];
            if(vis[v])
            {
                cn=v;
                isCircle[i/2]=true;
                vis[u]=false;
                return cn;
            }
            cn = dfs(v,i);
            if(cn!=-1)
            {
                isCircle[i/2]=true;
                vis[u]=false;
                if(cn == u)
                    return -1;
                
                return cn;
            }
        }
        vis[u]=false;
        return cn;
    }
    
    int inc[N],ouc[N];
    int e[N][2];
    int main()
    {
        memset(head,-1,sizeof(head));
        memset(vis,0,sizeof(vis));
        memset(isCircle,0,sizeof(isCircle));
        memset(inc,0,sizeof(inc));
        memset(ouc,0,sizeof(ouc));
        memset(ans,0,sizeof(ans));
        int i,n,u,v;
        scanf("%d",&n);
        int in0=n;
        for(i=0;i<n;i++)
        {
            scanf("%d%d",&u,&v);
            u--,v--;
            e[i][0]=u;
            e[i][1]=v;
            addedge(u,v,0);
            addedge(u,v,1);
            addedge(v,u,1);
            if(inc[v]==0)in0--;
            ouc[u]++;inc[v]++;
        }
        dfs(0,-1);
        bool first=true;
        for(i=0;i<n;i++)
        {
            if(!isCircle[i])continue;
            u=e[i][0];
            v=e[i][1];
            ouc[u]--;inc[v]--;
            if(inc[v]==0)in0++;
            if(in0 == 1 && inc[0] == 0)
            {
                ans[i]=true;
                if(!first)putchar(' ');
                printf("%d",i+1);
                first=false;
            }
            if(inc[v]==0)in0--;
            ouc[u]++;inc[v]++;
        }
        putchar('
    ');
        return 0;
    }
    View Code

    D.剑刃风暴

    虽说最近搞了MVPTree,也是跟查询点有关。。。但是这题没有给确定点,没法搞~~场上没做

    题目不能O(n3)(就是两两确定点,再向外探索点确定个数),会超时

    看了其他人的代码后才领悟,敢情是极角排序

    看下图就知道是怎么回事了。。。点要跟O点距离原点不足R,那么以自身点为中心,R半径的圆与O圆(半径同样为R)相交部分就是原点的可选范围。

    再加入一个点,只要对应圆也包含原来可选范围的一部分,这一部分的原点画的圆也能包含新点

    就像这样:

    红色区域包含3个圆,仔细观察就会发现其实就是蓝色扇形与棕色扇形对应角相交的部分

    可以大胆推断,新点与O点相交角包含区域可默认为可选区域

    区域包含的角越多,包含的对应点也越多

    然后代码就是这样:(场上排第2名的代码,除开排版问题比较容易看懂)

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    
    #define Mn 2005//平面点集中点数
    
    using namespace std;
    
    const double eps = 1e-9;//精度调高点没跑~
    const double pi = acos(-1.0);
    
    #define sqr(x) ((x) * (x))
    
    double R;//定长
    
    struct point
    {
      double x,y;
      void read()
      {
        scanf("%lf%lf",&x,&y);
      }
    
      void print()
      {
        printf("%lf%lf
    ",x,y);
      }
    
      double friend dis(const point &a,const point &b)
      {
        return sqrt(sqr(a.x - b.x) + sqr(a.y - b.y));
      }
    
    } p[Mn + 5];
    
    struct alpha
    {
    
      double v;
      bool flag;
      bool friend operator <(const alpha &a,const alpha &b)//排序专用偏序关系
      {
        return a.v < b.v;
      }
    
    } alp[Mn * Mn + 5]; //C(N,2)*2的可能交点(可能极角)
    
    void solve(int n,int r)
    {
      R = r;//本题内为单位圆
      for(int i = 0; i < n; i++)
        p[i].read();
    
      int MAX = 0;
      for(int i = 0; i < n; i++)
      {
        int t = 0;
        for(int j = 0; j < n; j++)
        {
          if(i == j)
            continue;
    
          double theta,phi,D;
          D = dis(p[i],p[j]);
          if(D > 2.0 * R)//距离超界直接秒杀
            continue;
    
    //关键部分
          theta = atan2(p[j].y - p[i].y,p[j].x - p[i].x);
          if(theta < 0)
            theta += 2 * pi;
          phi = acos(D / (2.0 * R));
          alp[t].v = theta - phi + 2 * pi;
          alp[t].flag = true;
          alp[t + 1].v = theta + phi + 2 * pi;
          alp[t + 1].flag = false;
          t += 2;
        }
    
        sort(alp,alp + t);
        int sum = 0;
        for(int j = 0; j < t; j++)
        {
          if(alp[j].flag)
            sum ++;
          else
            sum --;
          if(sum > MAX)
            MAX = sum;
        }
      }
      printf("%d
    ",MAX + 1);
    }
    
    int main()
    {
        int n,r;
        while(~scanf("%d%d",&n,&r))
        {
            solve(n,r);
        }
    }
    View Code
  • 相关阅读:
    MRC和ARC混合开发
    创建静态库.a
    IOS 数据存储之 FMDB 详解
    AFNETWorking的使用
    日历demo
    iOS开发系列--通知与消息机制
    paypal支付说明
    支付宝路径的问题
    iOS开发多线程篇—GCD介绍
    回调的具体最弱智的解释
  • 原文地址:https://www.cnblogs.com/dgutfly/p/6718983.html
Copyright © 2011-2022 走看看