前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >HDU 2011 菜鸟杯

HDU 2011 菜鸟杯

作者头像
用户1624346
发布2018-04-17 16:01:18
5760
发布2018-04-17 16:01:18
举报
文章被收录于专栏:calmoundcalmound

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

代码语言:javascript
复制
#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:纯水

代码语言:javascript
复制
#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距离的最小值即可。

代码语言:javascript
复制
#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

代码语言:javascript
复制
#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,

规律一出来 ,纯水

代码语言:javascript
复制
#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的个数

代码语言:javascript
复制
#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窜,暴力~~~~

代码语言:javascript
复制
#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,所以说一定要仔细分析题目,

代码语言:javascript
复制
#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:

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2012-08-22 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档