zoukankan      html  css  js  c++  java
  • HDU 2011 菜鸟杯

    A:该题写了很久,一直TLE,主要是枚举到n/2时间复杂度实在太高了,其实嘛,这道题就是因式分解,所以就是i*i=n,也就是sqrt(n)

    #include<stdio.h>
    #include<math.h>
    
    int main()
    {
        int n,T,i;
        int a,b;
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&n);
            for(i=sqrt(1.0*n); i>=1; i--)
            {
                if(n%i==0)
                {
                    a=i;
                    b=n/i;
                    if(a<b) {int t=a;a=b;b=t;}
                    if((a+b)%2==0 && (a-b)%2==0 && a!=b)//拆分后,组成二元一次方诺
                    {
                        break;
                    }
                }
            }
            if(i==0) printf("-1\n");
            else printf("%d\n",(a-b)/2);
    
        }
        return 0;
    }

    B:纯水

    #include<stdio.h>
    #include<math.h>
    
    int Is_what(char ch)
    {
        if(ch>='0' && ch<='9') return 1;
        return 0;
    }
    int main()
    {
        char str[10010];
        int i,j,ans,T;
        while(scanf("%d",&T)!=EOF)
        {
            scanf("%s",str);
            for(i=0; str[i]; i+=5)
            {
                ans=0;
                for(j=i; j<5+i; j++)
                {
                    int t=Is_what(str[j]);
                    if(t==1) ans+=pow(2,4-j+i);
                }
                printf("%c",ans+65);
            }
            printf("\n");
        }
    }

    C:给两个炮台和许多个敌人的坐标,问两个炮台的射程分别是多少的时候,可以既覆盖所有敌点,又花费最少(R1^2+R2^2)

    错误思路:刚开始是依次求出每个点到炮台disA和disB,比较两个大小,若A>B,则将该点赋予B炮台,这种思路是错的,比如AB距离为100,他们中点旁边各有1个敌人,根据这种思路得到的距离为49*49 + 49 * 49 = 4802,而如果只用A,则只需要51 * 51 = 2601.所以这种思路是错误的。(这种反例数据很好)。

    正确思路:将所有敌人距离A的距离从大到小排序,然后枚举A的半径,则B的半径就是A无法覆盖的点中距离B最远的距离。然后用一个变量维护A和B距离的最小值即可。

    #include<stdio.h>
    #include<algorithm>
    using namespace std;
    
    const int MAXN=100010;
    
    struct PNT
    {
        int x,y;
        int disA,disB;
    }p1,p2,pnt[MAXN];
    
    int _dist(PNT a,PNT b)
    {
        return (a.x-b.x)*(a.x-b.x)+(a.y-b.y)*(a.y-b.y);
    }
    
    bool cmp(PNT a,PNT b)
    {
        return a.disA>b.disA;
    }
    
    int main()
    {
        int T,n;
        int i;
        scanf("%d",&T);
        while(T--)
        {
           scanf("%d%d%d%d",&p1.x,&p1.y,&p2.x,&p2.y);
           scanf("%d",&n);
           for(i=0;i<n;i++)
           {
               scanf("%d%d",&pnt[i].x,&pnt[i].y);
               pnt[i].disA=_dist(p1,pnt[i]);
               pnt[i].disB=_dist(p2,pnt[i]);
           }
           sort(pnt,pnt+n,cmp);
           int res=pnt[0].disA;
           int ans=0;
           /*由于A已经排序了,所以没有涉及的地方就是没有覆盖的,因为他必定比临界的那点要大
             所以可以直接查找那些没涉及的B的最大值(当前的点,以前最大的记录点)
           */
           for(i=1;i<n;i++)
           {
               ans=max(ans,pnt[i-1].disB);
               res=min(res,ans+pnt[i].disA);
           }
           //A一个点都没有涉及
           ans=max(pnt[n-1].disB,ans);
           res=min(res,ans);
           printf("%d\n",res);
        }
    }

     D:

     E:水题ABC分别代表不同的值,给你几窜ABC求几窜中的一窜总和最小的

       还是wa的找不出来错误,错在当把ABC的记过预处理的,数组ch必须定义成int而不是char

    #include<stdio.h>
    #include<algorithm>
    int main()
    {
        char ch[100];
        int n,B,D,f,F;
    
        char str[1000000];
        while(scanf("%d",&n)!=EOF)
        {
            scanf("%d%d%d%d",&B,&D,&f,&F);
            int res=10000000;
            getchar();
            while(n--)
            {
                gets(str);
                int ans=0;
                for(int i=0; str[i]; i++)
                {
                    if(str[i]=='A') ans+=B+D+f;
                    if(str[i]=='B') ans+=B*2+D*2+F;
                    if(str[i]=='C') ans+=B*3+D*3+F*2;
                }
                if(res>ans) res=ans;
            }
            printf("%d\n",res);
        }
        return 0;
    }

     F:这个坑爹。。。。规律完全看不出来,看解题报告后恍然大悟,

    S(1)=1,
    S(2)=11,(1个1)
    S(3)=21,(2个1)
    S(4)=1211,(1个2,1个1)
    S(5)=111221,(1个1,1个2,2个1)
    S(6)=312211,

    规律一出来 ,纯水

    #include<stdio.h>
    #include<string.h>
    
    int num[50];
    char str[35][5000];
    
    int Find(int t,char ss[])
    {
        int i;
        for(i=t;ss[i];i++)
        {
            if(ss[i]!=ss[i+1]) return i;
        }
        return i;
    }
    
    void init()
    {
        strcpy(str[1],"1");
       // printf("%s\n",str[1]);
        num[1]=1;
        for(int i=2;i<=30;i++)
        {
            int cas=0;
            for(int j=0;str[i-1][j];j++)
            {
                int t=Find(j,str[i-1]);
                int cnt=t-j+1;
                str[i][cas++]=cnt+'0';
                str[i][cas++]=str[i-1][j];
                j=t;
            }
            str[i][cas]='\0';
           // printf("%s\n",str[i]);
            num[i]=strlen(str[i]);
        }
    }
    
    int main()
    {
        int n;
        init();
        while(scanf("%d",&n)!=EOF)
        {
           if(n==0) break;
           printf("%d\n",num[n]);
        }
        return 0;
    }

     G:这道题是我认为,新生赛中出的最好的,并没涉及算法,但是思路真的很不错,开阔了思维,隐藏的信息十分巧妙

        现在给出我的理解,将所有数全部转换成二进制,进行一位一位的判断。

        现假设8个数字分别为x1,x2。。。x8,总和为sum。

        当8个数字的相同位上的数的1有奇数个(需考虑进位),那么无论这8个数字相加后依旧是奇数,所以此时若判断sum的同位置就可以,若sum的该位为0,则m的该位1,

       若sum的该位0,则sum的该位为0;(假若进位的数是奇数,该位的1也是奇数,相加后是偶数,则说明该位的1本就是偶数个的)

       由此推断:

      1的个数偶数,sum同位为0,m的同位置为0,1的个数是1

                         sum同位为0,m的同位置为1,0的个数是1

                奇数,sum同位为0,m的同位置为1,0的个数是1

                         sum同位为0,m的同位置为0,1的个数是1

    关键是进位:若m为1,则进位的1,是1^其同一位置的0得到的,8-p就是0的个数

    #include<stdio.h>
    #include<math.h>
    int main()
    {
        int T,i,sum;
        int x[9];
        int ans[100];
        scanf("%d",&T);
        while(T--)
        {
            for(i=0; i<8; i++)
                scanf("%d",&x[i]);
            scanf("%d",&sum);
            int p;//记录有几个1
            int t=0;//记录需要进位的
            int cas=0;
            int flag;
            while(1)
            {
                flag=0;
                p=0;
                for(i=0; i<8; i++)
                {
                    if(x[i]&1)
                    {
                        p++;
    
                    }
                    if(x[i]!=0) flag=1;
                    x[i]>>=1;
                }
                if(flag==0 && t==0) break;
                if((t+p)%2==0)//偶数
                {
                    if(sum&1)//sum为1,则sum该位为1
                    {
                        t=(8-p+t)/2;
                        ans[cas++]=1;
                    }
                    else
                    {
                        t=(t+p)/2;
                        ans[cas++]=0;
                    }
                }
                else
                {
                    if(sum&1)
                    {
                        t=(t+p)/2;
                        ans[cas++]=0;
                    }
                    else
                    {
                        t=(t+8-p)/2;
                        ans[cas++]=1;
                    }
                }
                sum>>=1;
            }
            int m=0,res=1;
            //printf("%d\n",cas);
            for(i=0; i<cas; i++)
            {
                m+=res*ans[i];
                res*=2;
            }
            printf("%d\n",m);
        }
        return 0;
    }

    H:求a窜中最多含多少个b窜,暴力~~~~

      

    #include<stdio.h>
    #include<string.h>
    
    const int MAXN=1000010;
    char str1[MAXN],str2[10];
    int Find(int t)
    {
        int cas=0,i;
        for(i=0;str2[i];i++)
        {
            if(str2[i]!=str1[t++]) return -1;
        }
        return i;
    }
    
    int main()
    {
        int T;
        int i,t;
        scanf("%d",&T);
        while(T--)
        {
            int ans=0;
            scanf("%s%s",str1,str2);
            int len2=strlen(str2);
            for(i=0;str1[i];i++)
            {
                if(str1[i]==str2[0])
                {
                    t=Find(i);
                    if(t==len2)
                    {
                        ans++;
                        i+=t-1;
                    }
                }
            }
            printf("%d\n",ans);
        }
        return 0;
    }

    I:这道题也很好,通过这道题,让我明白了,原来二分还可以这么用,数组a的下标记录的结果,而数组a的结果记录的输入值,是不是这个就是反哈希思路~~,二分也不单简简单  单的就是用”==“break,也可以让二分完。

    还有就是memset不要乱用,造成MLE,由于hash数组开的大了也造成MLE,所以说一定要仔细分析题目,

    #include<stdio.h>
    #include<string.h>
    const int MAXN=10000000;
    
    int a[MAXN],hash[10];
    int tot;
    
    void init()
    {
        int i,j;
        tot=1;
        for(i=1;i<=10000000;i++)
        {
            j=i;
            memset(hash,0,sizeof(hash));
            while(j)
            {
                if(hash[j%10]) break;
                hash[j%10]=1;
                j/=10;
            }
            if(j==0) a[tot++]=i;
        }
    }
    
    int main()
    {
        int n,res;
        init();
        while(scanf("%d",&n)!=EOF)
        {
            if(n<1) {printf("0\n"); continue;}
            int begin=1;
            int end=tot-1;
            int mid;
            while(begin<=end)
            {
                mid=(begin+end)/2;
                if(a[mid]<n)
                {
                    res=mid;
                    begin=mid+1;
                }
                else end=mid-1;
            }
            printf("%d\n",res);
        }
        return 0;
    }

      

    J:

  • 相关阅读:
    Spring MVC:框架及其组件介绍
    Goods:生成订单
    Goods:我的订单查询分页
    LeetCode:Kth Largest Element in an Array(need update)
    LeetCode:Swap Nodes in Pairs
    Goods:购物车条目加减数量实现
    LeetCode:Sum Root to Leaf Numbers
    Goods:购物车模块之全选按钮与条目之复选按钮的click事件
    Goods:查询某个用户的购物车条目以及添加购物车条目
    洛谷2387 NOI2014魔法森林(LCT维护最小生成树)
  • 原文地址:https://www.cnblogs.com/zsboy/p/2650262.html
Copyright © 2011-2022 走看看