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:

posted @ 2012-08-22 09:48  calmound  阅读(571)  评论(0编辑  收藏  举报