2014年携程程序设计大赛 预赛第一场 A,B,C

本文包含三道算法竞赛题目的详细解答,涉及数论、动态规划及最小生成树等核心算法概念。通过具体代码实现展示了如何求解特定数学问题、优化括号序列以及计算最短路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

A. 

题解:

     反面来想...一个数列如果到不了-1..说明这个数列所有数的最大公约数不是1...所以用B^A-到不了的数目=答案..

Program:

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define ll long long
#define oo 1<<29
#define MAXN 100000+5
using namespace std;
ll sum,A,B,P[21]={0,2,3,5,7,11,13,17,19,23};
int gcd(int a,int b)
{
       if (a%b==0) return b;
       return gcd(b,a%b);
}
ll POW(ll p,int k)
{
       ll x=1;
       while (k--) x*=p;
       return x;       
}
void dfs(ll now,ll data,ll num)
{
       ll m=0,j; 
       if (B%data!=0) return;
       for (j=data;j<=B;j++)
          if (j%data==0) m++;
       if (num%2) sum+=POW(m,A);
             else sum-=POW(m,A);
       for (now=now+1;now<=8;now++) 
             dfs(now,data*P[now],num+1);  
}
int main()
{
       ll k,x; 
       freopen("input.txt","r",stdin);
       freopen("output.txt","w",stdout);
       scanf("%I64d",&k);
       while (k--)
       {
               scanf("%I64d%I64d",&A,&B);
               sum=0;
               for (x=1;x<=8;x++) dfs(x,P[x],1);
               printf("%I64d\n",POW(B,A)-sum);
       }
       return 0;
}


B.

题解:

     很简单的二位dp..dp[l][r]代表区间[l,r]为一个合法的括号序列所需要加的最少括号..

Program:

#include<iostream>
#include<algorithm>
#include<string.h>
#include<stdio.h>
#include<queue>
#include<stack>
#include<map>
#include<set>
#define ll long long
#define oo 1<<29
#define MAXN 100+5
using namespace std; 
int dp[MAXN][MAXN];
char s[MAXN];
int count(int l,int r)
{
       if (s[l]=='(' && s[r]==')') return 0;
       if (s[l]=='[' && s[r]==']') return 0;
       return 2;
}
int main()
{ 
       int k,len,LEN,x,l,r,i;
       freopen("input.txt","r",stdin);
       freopen("output.txt","w",stdout);
       scanf("%d",&k); 
       while (k--)
       {
               scanf("%s",s+1);
               len=strlen(s+1); 
               memset(dp,0x7f,sizeof(dp)); 
               for (x=1;x<=len;x++) dp[x][x]=1,dp[x+1][x]=0;
               for (LEN=1;LEN<len;LEN++)
                  for (x=1;x<=len-LEN;x++)
                  {
                         l=x,r=x+LEN;
                         dp[l][r]=dp[l+1][r-1]+count(l,r);
                         dp[l][r]=min(dp[l][r],dp[l+1][r]+1); 
                         dp[l][r]=min(dp[l][r],dp[l][r-1]+1);
                         for (i=l;i<r;i++)
                            dp[l][r]=min(dp[l][r],dp[l][i]+dp[i+1][r]);
                  }    
               printf("%d\n",dp[1][len]);
       }
       return 0;
}


C.

题解:

     主要是要算下球面距离公式.然后就是裸的最小生成树了.

Program:

#include<iostream>
#include<algorithm>
#include<string.h>
#include<stdio.h>
#include<queue>
#include<cmath>
#include<stack>
#include<map>
#include<set>
#define ll long long
#define oo 1<<29
#define MAXN 100+5
#define eps 1e-5
using namespace std; 
const double pi=3.14159265358979323846;
struct point
{
       double x,y;
}P[MAXN];
double D,L,sum,m,A[MAXN][MAXN];
bool used[MAXN];
double calc(point a,point b)
{
       double ans=(D/2)*acos(sin(a.x)*sin(b.x)+cos(a.x)*cos(b.x)*cos(a.y-b.y));
       return ans;
}
int main()
{ 
       int k,C,t,i,j,x;
       freopen("input.txt","r",stdin);
       freopen("output.txt","w",stdout);
       scanf("%d",&k); 
       while (k--)
       {
              scanf("%lf%lf",&D,&L);
              scanf("%d",&C);
              for (i=1;i<=C;i++)
              {
                     scanf("%lf%lf",&P[i].x,&P[i].y);
                     P[i].x=P[i].x/180*pi;
                     P[i].y=P[i].y/180*pi;
              }
              for (i=1;i<=C;i++)
                for (j=1;j<=C;j++)
                   A[i][j]=calc(P[i],P[j]);
              sum=0;
              memset(used,0,sizeof(used));
              used[1]=true;
              for (t=2;t<=C;t++)
              {
                      m=-1;
                      for (i=1;i<=C;i++)
                        if (used[i])
                          for (j=1;j<=C;j++)
                            if (!used[j])
                               if (A[i][j]<m || m<0) 
                                 m=A[i][j],x=j;
                      sum+=m;
                      used[x]=true;
              }
              if (L>=sum) puts("Y");
                     else puts("N");
       }
       return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值