CodingTrip - 携程编程大赛 (预赛第一场)

聪明的猴子

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 1123    Accepted Submission(s): 294


Problem Description
  
  
森林中有一排香蕉树(无限长),一只猴子站在其中一棵树上,猴子在跳跃前要先抽取一张卡片,卡片上写有A+1个自然数,其中最后一个是B,前A个数只能小于等于B,卡片上的数字可以相同。猴子每次跳跃先从卡片上任选一个自然数C,然后向左、或向右跳C棵树。猴子的任务是:跳到与它左边相邻的香蕉树上时,就可以吃掉上面的香蕉。 例如,当A=2,B=4时,对于卡片(2, 3, 4),猴子就可以吃到香蕉:它可以先向左跳3棵树,再向右跳两棵树。而对于卡片(2, 2, 4),猴子则怎么也不可能跳到它左边相邻的香蕉树上。 当确定A和B后,则一共可以有B^A张不同的卡片。问题是,在这所有的卡片中,有多少张可以让猴子完成任务。
 

Input
  
  
第1行k,表示有k组测试数据,k<=100 第2至k+1行,每行两个自然数A和B,以一个空格分开 (A<= 10 , B <= 20)。
 

Output
  
  
共k行,每行的数字代表每组数据中,可以让猴子跳到它左边相邻香蕉树的卡片数。
 

Sample Input
  
  
3 2 3 4 8 5 13
 

Sample Output
  
  
8 3840 371292
 
给你两个正整数n,m,让你求长度为n+1的满足条件的一个等式:a[1]*x1+a[2]*x2+a[3]*x3+...+a[n]*xn+a[n+1]*x(n+1)=1 (0<=a[i]<=m&&a[n+1]=m)
让你求一共有多少种情况满足这个条件。
要使得a[1]*x1+a[2]*x2+a[3]*x3+...+a[n]*xn+a[n+1]*m=1 (0<=a[i]<=m),那么a[1],a[2],a[3]....a[n+1]的最大公约数为1.
要解决此题,你需要知道的知识有扩展欧几里得,鸽巢原理,以及递归求所有的排列组合。
例如:n=2,m=360 
360=3^2*2^3*5  所有不满足条件的数列,最大公约数是360质因子的乘积,只要将这些组合去掉,就是要求的答案(不懂的慢慢揣摩)
那么就要先求出m的所有质因子,然后求出总的排列组合的个数,即题目中说的M^N,最后根据鸽巢原理求得最后答案。
公式为:ans=M^N-(有奇数个公因数的n元组)+(有偶数个公因数的n元组)。拿上面的例子来说就是
ans=m^n-(有公因数2的n元组)- (有公因数3的n元组)- (有公因数5的n元组)+ (有公因数2,3的n元组) +(有公因数2,5的n元组)+ (有公因数3,5的n元组)- (有公因数2,3,5的n元组).
有公因数d的n元组,每个位置上有 (m/d)个选择(1 ~ m里面有m/d个d的倍数),根据乘法原理,可以得出有公因数d的n元组有 (m/d)^n 个.
//400K    0MS
#include<stdio.h>
#define M 130007
long long num[M],s[M];
long long n,m,total,per;
void sum_factor()//分解质因子,存在num里面
{
    total=0;
    long long t=m;
    for(int i=2;i*i<=t;i++)
    {
        if(t%i==0)num[total++]=i;
        while(t%i==0)t/=i;
    }
    if(t!=1)num[total++]=t;
}
long long pow(long long x,long long y)//求x^y
{
    long long k=x;
    for(long long i=1;i<y;i++)
        x*=k;
    return x;
}
void dfs(long long a,long long b,long long c)//a在数组中的起始位置,b含的个数,c公共质因子的个数
{
    if(b==c)
    {
        long long t=m;
        //printf("(");
        for(long long i=0;i<c;i++)
        {
            //printf("%d ",s[i]);
            t/=s[i];//t表示每位上有几个包含质因子的数
        }
        //printf(")\n");
        per+=pow(t,n);//总共有多少个
    }
    else
    {
        for(long long i=a;i<total;i++)//递归回溯求解所有排列组合
        {
            s[b]=num[i];
            dfs(i+1,b+1,c);
        }
    }
}
int main()
{
    int k;
    scanf("%d",&k);
    while(k--)
    {
        scanf("%I64d%I64d",&n,&m);
        sum_factor();
        long long ans=pow(m,n);
        for(long long i=1;i<=total;i++)
        {
            per=0;
            dfs(0,0,i);
            if(i%2)ans-=per;//如果有奇数个公因数的n元组就相减
            else ans+=per;//如果有奇数个公因数的n元组就相加
        }
        printf("%I64d\n",ans);
    }
    return 0;
}

携程全球数据中心建设

Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 725    Accepted Submission(s): 307


Problem Description
   
   
携程为了扩展全球在线旅游业务,决定在全球建设多数据中心,以便提高网站的访问速度和容灾处理。 为了实现每个数据中心的数据能互通,数据中心之间需要通过光纤连接。为了节约光纤成本,我们计划采用点对点方式来达到最终各个数据中心的数据互通,每个数据中心本身都可以作为数据中转站。做为全球多数据中心设计者,您需要知道最短的光纤总长度,来把所有的数据中心都实现互通。假设地球是个圆球,且表面是平滑的,并且没有任何阻碍物(河流,山脉)。 输入数据是一组数据中心的经纬度 纬度: -90° 到 +90° 经度: -180° 到 +180° (圆周率pi= 3.14159265358979323846)
 

Input
   
   
第一行第一个整数N(1≤N≤100),表示有多少个用例. 每个用例包含了: 第一行,小数D(1≤D≤1,000,000),表面圆球的直径(公里). 第二行,小数L(1≤L≤1,000,000) 光纤总长度 (公里). 第三行,整数C(1≤C≤100) ,表示数据中心的数量. 接下来的C行, 每行有2个形如"X Y"的小数,表示每个数据中心的纬度(-90≤X≤90)和经度 (-180≤Y≤180).
 

Output
   
   
每个用例输出一行. 如果光纤长度L足够连接所有数据中心,输出"Y", 否则输出"N"。
 

Sample Input
   
   
2 12742 5900 3 51.3 0 42.5 -75 48.8 3 12742 620 2 30.266 97.75 30.45 91.1333
 

Sample Output
   
   
Y N

如何通过地球上两点上的经维度求他们的距离公式?
设球的半径为R,并且假设东经为正,西经为负,北纬为正,南纬为负。
则A(x,y)坐标可表示为(R*cosy*cosx, R*cosy*sinx, R*siny)
B(a,b)坐标可表示为(R*cosb*cosa, R*cosb*sina, R*sinb)
AB两点的的球面距离为:R*(arccos(cosb*cosy*cos(a-x)+sinb*siny))
最后直接最小生成树即可。
#include<stdio.h>
#include<string.h>
#include<math.h>
#define MAX 99999999
const double pi=3.14159265358979323846;
double g[110][110],lgtd[110],lttd[110];

int c;
void init()
{
    for(int i=1;i<107;i++)
        for(int j=1;j<107;j++)
            g[i][j]=MAX;
}
double prime()
{
    double low[110];
    int flag[110];
    memset(flag,0,sizeof(flag));
    for(int i=1; i<=c; i++)
    {
        low[i]=g[1][i];
    }
    double count=0;
    flag[1]=1;
    for(int i=1; i<c; i++)
    {
        double min=MAX+1;
        int k;
        for(int j=1; j<=c; j++)
        {
            if(flag[j]==0&&min>low[j])
            {
                min=low[j];
                k=j;
            }
        }
        flag[k]=1;
        count+=low[k];
        for(int j=1; j<=c; j++)
        {
            if(flag[j]==0&&low[j]>g[j][k])
            {
                low[j]=g[j][k];
            }
        }
    }
    return count;
}
int main()
{
    int t;
    double d,l,lgtd[110],lttd[110];
    scanf("%d",&t);
    while(t--)
    {
        scanf("%lf%lf%d",&d,&l,&c);
        for(int i=1;i<=c;i++)
        {
            scanf("%lf%lf",<td[i],&lgtd[i]);
            //弧度=角度*π/180
            lgtd[i]=lgtd[i]*pi/180;
            lttd[i]=lttd[i]*pi/180;
        }
        d/=2;
        for(int i=1;i<=c;i++)
            for(int j=1;j<=c;j++)
            {
                if(i!=j)
                g[i][j]=d*acos(cos(lttd[j])*cos(lttd[i])*cos(lgtd[i]-lgtd[j])+sin(lttd[i])*sin(lttd[j]));
            }
        double ans=prime();
        if(ans>l)printf("N\n");
        else printf("Y\n");
    }
    return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值