华北水利水电大学AI.Coder程序设计挑战赛正式赛题解

A.计数问题

题目描述

试计算在区间1到n的所有整数中,数字x(0≤x≤9)共出现了多少次?例如,在1到11中,即在1、2、3、4、5、6、7、8、9、10、11中,数字1出现了4次。

输入

每组输入数据共1行,包含2个整数n、x,之间用一个空格隔开。

数据规模:

对于100%的数据,1≤n≤1000000,0≤x≤9。

输出

每组输出共1行,包含一个整数,表示x出现的次数。

样例输入

11 1

样例输出

4

思路:暴力,签到。

代码如下:

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string>
#include<set>
#include<math.h>
#include<map>
#include<string.h>
#include<stack>
#include<queue>
#define per(i,a,b) for(int i=a;i<=b;++i)
#define rep(i,a,b) for(int i=a;i>=b;--i)
#define inf 0x3f3f3f 
using namespace std;
int main()
{
    int n,x;    
    scanf("%d%d",&n,&x);
    char s[8];
    int p[10]={0};
    per(i,1,n)
    {
        sprintf(s,"%d",i);
        per(j,0,strlen(s)-1)
        p[s[j]-'0']++;
    }
    printf("%d\n",p[x]);
    return 0;
}

B.单词接龙

题目描述

单词接龙是一个与我们经常玩的成语接龙相类似的游戏,现在我们已知一组单词,且给定一个开头的字母,要求出以这个字母开头的最长的“龙”(每个单词都最多在“龙”中出现两次),在两个单词相连时,其重合部分合为一部分,例如beast和astonish,如果接成一条龙则变为beastonish,另外相邻的两部分不能存在包含关系,例如at和atide间不能相连。

输入

每个测试文件只包含一组测试数据,每组输入的第一行为一个单独的整数n(n<=20)表示单词数,以下n行每行有一个单词,输入的最后一行为一个单个字符,表示“龙”开头的字母。你可以假定以此字母开头的“龙”一定存在。

输出

对于每组输入数据,输出以此字母开头的最长的“龙”的长度。

下面的测试样例最后连成的“龙”为atoucheatactactouchoose。

样例输入

5
at
touch
cheat
choose
tact
a

样例输出

23

思路:预处理重复部分,因为数据小可使用搜索。赛后A,,,心累。

代码如下:

#include<iostream>
#include<cstring>
#define per(i,a,b) for(int i=a;i<=b;++i)
#define rep(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
int n,p[22],vis[22],l,ans,mp[21][21]; 
string s[21];
int fun(string a,string b)
{
    int w=min(a.length(),b.length());
    per(i,1,w)
      if(a.substr(a.length()-i,i)==b.substr(0,i))//判断后半段与前半段是否相等 
      return b.length()-i;//返回去重后的长度 
    return 0;
}
void dfs(int a,int c)//a为当前第几节躯干,c为长度 
{
    per(i,1,n)
    {
        if(mp[p[a]][i]!=0&&vis[i]<2)//可连接且使用次数小于2 
        {
            p[a+1]=i;//指向上一节 
            l+=mp[p[a]][i];//加长度 
            vis[i]++;
            ans=max(l,ans);
            dfs(a+1,l);
            l-=mp[p[a]][i];
            vis[i]--;
        }
    }
}
int main()
{
    cin>>n;
    char a;
    per(i,1,n) cin>>s[i];
    cin>>a;
    per(i,1,n)//预处理 
    {  
	    if(s[i][0]==a) 
		mp[0][i]=s[i].length();//可以接龙头的长度 
    }
    per(i,1,n)
    {
        per(j,1,n)
        { 
            mp[i][j]=fun(s[i],s[j]);//判断是否可连接,返回去重后的长度 
            //cout<<mp[i][j]<<"*";
        } //cout<<endl;
    } 
    dfs(0,0);
    cout<<ans;
    return 0; 
}

C.乒乓球

题目描述

国际乒联现在主席沙拉拉自从上任以来就立志于推行一系列改革,以推动乒乓球运动在全球的普及。其中11分制改革引起了很大的争议,有一部分球员因为无法适应新规则只能选择退役。华华就是其中一位,他退役之后走上了乒乓球研究工作,意图弄明白11分制和21分制对选手的不同影响。在开展他的研究之前,他首先需要对他多年比赛的统计数据进行一些分析,所以需要你的帮忙。

华华通过以下方式进行分析,首先将比赛每个球的胜负列成一张表,然后分别计算在11分制和21分制下,双方的比赛结果(截至记录末尾)。
比如现在有这么一份记录,(其中W表示华华获得一分,L表示华华对手获得一分):
      WWWWWWWWWWWWWWWWWWWWWWLW
在11分制下,此时比赛的结果是华华第一局11比0获胜,第二局11比0获胜,正在进行第三局,当前比分1比1。而在21分制下,此时比赛结果是华华第一局21比0获胜,正在进行第二局,比分2比1。如果一局比赛刚开始,则此时比分为0比0
你的程序就是要对于一系列比赛信息的输入(WL形式),输出正确的结果。

输入

每个输入文件包含若干行字符串(每行至多20个字母),字符串有大写的W、L和E组成。其中E表示比赛信息结束,程序应该忽略E之后的所有内容。

输出

输出由两部分组成,每部分有若干行,每一行对应一局比赛的比分(按比赛信息输入顺序)。其中第一部分是11分制下的结果,第二部分是21分制下的结果,两部分之间由一个空行分隔。

样例输入

WWWWWWWWWWWWWWWWWWWW
WWLWE

样例输出

11:0
11:0
1:1

21:0
2:1

提示

注意:乒乓球比赛每局结束规则:一方胜另一方2球,本局结束,记录比分比赛双方任一一方达到11分或21分且领先对手两分,此时比赛结束(可能存在41:40这种情况)

思路:真的不想吐槽,比赛时题面有问题后面才改的,害我wa12发。2种情况,a或b到达11,且相差大于等于2,ab都大于11,且相差大于等于2.然后直接模拟即可。

代码如下:

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string>
#include<set>
#include<math.h>
#include<map>
#include<string.h>
#include<stack>
#include<queue>
#define per(i,a,b) for(int i=a;i<=b;++i)
#define rep(i,a,b) for(int i=a;i>=b;--i)
#define inf 0x3f3f3f 
using namespace std;
int main()
{
    char ch,s[1000000];
    int a=0,b=0,k=0,A=0,B=0;
    while(ch=getchar())
    {
          
        //if(ch=='\n') continue;
        s[k]=ch;k++;
        if(ch=='E')
        {
            printf("%d:%d\n",a,b);a=0,b=0;
            break;
        }
        if(ch=='W') a++;
        if(ch=='L') b++;    
        if((a>=11&&abs(a-b)>=2)||(abs(b-a)>=2&&b>=11)||(abs(a-b)==2&&a>=11&&b>=11))
        {
            printf("%d:%d\n",a,b);
            a=0,b=0;
        }
    }
    printf("\n");
    per(i,0,k-1)
    {
        //cout<<s[i]<<"*";
        if(s[i]=='E')
        {
            printf("%d:%d\n",a,b);
            break;
        }
        if(s[i]=='W') a++;
        if(s[i]=='L') b++;
        if((a>=21&&abs(a-b)>=2)||(b>=21&&abs(b-a)>=2)||(a>=21&&b>=21&&abs(a-b)==2))
        {
            printf("%d:%d\n",a,b);
            a=0,b=0;
        }
    }
    return 0;
}

D.亲戚

题目描述

        或许你并不知道,你的某个朋友是你的亲戚。他可能是你的曾祖父的外公的女婿的外甥女的表姐的孙子。如果能得到完整的家谱,判断两个人是否亲戚应该是可行的,但如果两个人的最近公共祖先与他们相隔好几代,使得家谱十分庞大,那么检验亲戚关系实非人力所能及。在这种情况下,最好的帮手就是计算机。为了将问题简化,你将得到一些亲戚关系的信息,如Marry和Tom是亲戚,Tom和Ben是亲戚,等等。从这些信息中,你可以推出Marry和Ben是亲戚。请写一个程序,对于我们的关于亲戚关系的提问,以最快的速度给出答案。

输入

输入由两部分组成。
第一部分以N,M开始。N为问题涉及的人的个数(1≤N≤20000)。这些人的编号为123… N。下面有M行(1≤M≤1 000 000),每行有两个数ai bi,表示已知ai和bi是亲戚。
第二部分以Q开始。以下Q行有Q个询问(1≤Q≤1 000 000),每行为ci di,表示询问ci和di是否为亲戚。

输出

对于每个询问ci di,输出一行:若ci和di为亲戚,则输出“Yes”,否则输出“No”。

样例输入

10 7
2 4
5 7
1 3
8 9
1 2
5 6
2 3
3
3 4
7 10
8 9

样例输出

Yes
No
Yes

思路:并查集+压缩路径至根节点呗。

代码如下:

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string>
#include<set>
#include<math.h>
#include<map>
#include<string.h>
#include<stack>
#include<queue>
#define per(i,a,b) for(int i=a;i<=b;++i)
#define rep(i,a,b) for(int i=a;i>=b;--i)
#define inf 0x3f3f3f 
using namespace std;
long long int p[20005],n;
void init()
{
    per(i,1,n)
    {
        p[i]=i;
    }
}
long long int findset(long long int v)
{
    long long int t1,t2=v;
    while(v!=p[v])
    {
        v=p[v];
    }
    while(t2!=p[t2])
    {
        t1=p[t2];
        p[t2]=v;
        t2=t1;
    }
    return v;
}
void bin(long long int a,long long int b)
{
    long long int a1=findset(a);
    long long int b1=findset(b);
    if(a1!=b1)
    {
        p[a1]=b1;
    }
}
int main()
{
    long long int m,t,a,b;
    cin>>n>>m;
    init();
    while(m--)
    {
        cin>>a>>b;
        bin(a,b);
    }
    //per(i,1,n) cout<<p[i]<<"*";
    cin>>t;
    while(t--)
    {
        cin>>a>>b;
        while(p[a]!=a)
        {
            a=p[a];
        }
        while(p[b]!=b)
        {
            b=p[b];
        }
        if(a==b) printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}

E.回文数

题目描述

我们把从左往右和从右往左念起来相同的数字叫做回文数。例如,75457就是一个回文数。
当然某个数用某个进制表示不是回文数,但是用别的进制表示可能就是回文数。
例如,17是用十进制表示的数,显然它不是一个回文数,但是将17用二进制表示出来是10001,显然在二进制下它是一个回文数。
现在给你一个用十进制表示的数,请你判断它在2~16进制下是否是回文数。

输入

输入包含多组测试数据。每组输入一个用十进制表示的正整数n(0<n<50000),当n=0时,输入结束。

输出

对于每组输入,如果n在2~16进制中的某些进制表示下是回文数,则输出“Number i is palindrom in basis ”,在后面接着输出那些进制。其中i用n的值代替,后面输出的进制中,每两个数字之间空一个。
如果n在2~16进制的表示下都不为回文数,则输出“Number i is not a palindrom”,其中i用n的值代替。

样例输入

17
19
0

样例输出

Number 17 is palindrom in basis 2 4 16
Number 19 is not a palindrom

思路:模拟即可,没有坑点

代码如下:

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string>
#include<set>
#include<math.h>
#include<map>
#include<string.h>
#include<stack>
#include<queue>
#define per(i,a,b) for(int i=a;i<=b;++i)
#define rep(i,a,b) for(int i=a;i>=b;--i)
#define inf 0x3f3f3f 
using namespace std;
int n;
int fun(int k)
{
    int s[100000];
    int z=1,h=n;
    while(h!=0)
    {
        s[z]=h%k;//cout<<s[z];
        h=h/k;
        z++;
    }
    //cout<<"*";
    int i=1,j=z-1;
    if(z==2) return 1;
    if(j==2)
    {
        if(s[1]==s[2]) return 1;
        else return 0;
    } 
    //cout<<z<<"*";
    for(i=1,j=z-1;j>i;++i,--j)
    {
        if(s[i]!=s[j]) return 0;
    }
    return 1;
}
int main()
{
    while(cin>>n&&n!=0)
    {
        int p[17],l=0;
        per(i,2,16)
        {
            if(fun(i)==1) p[l]=i,l++;
        }
        if(l==0) printf("Number %d is not a palindrom\n",n);
        else
        {
            printf("Number %d is palindrom in basis",n);
            per(i,0,l-1) 
            {
                printf(" %d",p[i]);
            }
            printf("\n");
        }
    }
    return 0;
} 

F.最优布线问题

题目描述

学校有n台计算机,为了方便数据传输,现要将它们用数据线连接起来。两台计算机被连接是指它们间有数据线连接。由于计算机所处的位置不同,因此不同的两台计算机的连接费用往往是不同的。

   当然,如果将任意两台计算机都用数据线连接,费用将是相当庞大的。为了节省费用,我们采用数据的间接传输手段,即一台计算机可以间接的通过若干台计算机(作为中转)来实现与另一台计算机的连接。

 现在由你负责连接这些计算机,任务是使任意两台计算机都连通(不管是直接的或间接的)。

输入

输入文件wire.in,第一行为整数n(2<=n<=100),表示计算机的数目。此后的n行,每行n个整数。第x+1行y列的整数表示直接连接第x台计算机和第y台计算机的费用。

输出

输出文件wire.out,一个整数,表示最小的连接费用。

样例输入

3
0 1 2
1 0 1
2 1 0

样例输出

2

提示

注:表示连接1和2,2和3,费用为2

思路:最小生成树,没有坑点。

代码如下:

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string>
#include<set>
#include<math.h>
#include<map>
#include<string.h>
#include<stack>
#include<queue>
#define per(i,a,b) for(int i=a;i<=b;++i)
#define rep(i,a,b) for(int i=a;i>=b;--i)
#define inf 0x3f3f3f 
using namespace std;
 
int n,p[1000][1000],p1[1000][1000];
int d[1000];
int vis[1000]={0};
int prim()
{
    fill(d,d+n+1,inf);
    d[0]=0;
    int s=0;
    per(i,0,n-1)
    {
        int u=-1,minn=inf;
        per(j,0,n-1)
        {
            if(vis[j]==0&&d[j]<minn)
            {
                u=j;
                minn=d[j];
            }
        }
        if(u==-1) return -1;
        vis[u]=1;
        s+=d[u];
        per(v,0,n-1)
        {
            if(vis[v]==0&&p[u][v]!=inf&&p[u][v]<d[v])
            {
                d[v]=p[u][v];
            }
        }
    }
    return s;
}
int main()
{
    int a,b,c;
    cin>>n;
    per(i,0,n-1)
    {
        per(j,0,n-1)
        {
            cin>>p[i][j];
        }
    }
    /*per(i,1,n)
    {
        per(j,i+1,n)
        {
            p[i][j]=p1[i+1][j];
        }
    }*/
    printf("%d",prim());
    return 0;
}

G.修路

题目描述

SNJ位于HB省西部一片群峰耸立的高大山地,横亘于A江、B水之间,方圆数千平方公里,相传上古的神医在此搭架上山采药而得名。景区山峰均在海拔3000米以上,堪称"华中屋脊"。SNJ是以秀绿的亚高山自然风光,多样的动植物种,人与自然和谐共存为主题的森林生态区。

SNJ处于中国地势第二阶梯的东部边缘,由大巴山脉东延的余脉组成中高山地貌,区内山体高大,高低不平。 交通十分不便。

最近,HB省决定修一条从YC市通往SNJ风景区的高速公路。经过勘测分析,途中需要经过高度分别为H1,H2,……Hn的N个山区。由于高低不平,除正常的修路开支外,每段还要多出高度差|Hi - Hi-1|*X万元的斜坡费用。Dr. Kong 决定通过填高一些区域的高度来降低总的费用。当然填高也是需要一些费用的。每填高Y单位,需要付出Y2万元费用。

你能否帮Dr. Kong做出一个规划,通过部分填高工程改造,使得总的费用降下来。

输入

第一行: T 表示以下有T组测试数据 ( 1≤ T ≤8 ) 对每组测试数据, 第一行:N X (2 ≤ N ≤100,000 1≤ X ≤100) 第二行:N个整数,分别表示N个区域的高度Hi ( 1<=Hi<=100 i=1…. n)

输出

对每组测试数据,输出占一行,一个整数,即经过部分填高工程改造后的最少费用。

样例输入

1
5 2
2 3 5 1 4

样例输出

15

思路:河南省赛原题,鄙人不擅dp,暂时不会。

 

 

 

 

 

H.N皇后问题

题目描述

在N*N(1<N<=9)的棋盘上放置N个皇后而彼此不受攻击(即在棋盘的任一行,任一列和任一对角线上不能放置2个皇后),编程求解所有的摆放方法。

输入

一个整数n(1<n<=9)

输出

若有解,输出若干行,每行n个数,依次表示第i个皇后的列号
若无解,输出 “no”

样例输入

4

样例输出

2 4 1 3
3 1 4 2

思路:暴力搜索,记录一下位置。其实这题和全排列一模一样。

代码如下:

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string>
#include<set>
#include<math.h>
#include<map>
#include<string.h>
#include<stack>
#include<queue>
#define per(i,a,b) for(int i=a;i<=b;++i)
#define rep(i,a,b) for(int i=a;i>=b;--i)
#define inf 0x3f3f3f 
using namespace std;
int vis[10],n,p[10],s=0;
int p1[10];
void fun(int x)
{
    if(x==n+1)
    {
        int fag=1;
        per(i,1,n)
        {
            per(j,i+1,n)
            {
                if(abs(i-j)==abs(p[i]-p[j]))
                fag=0;
            }
        }
        if(fag) 
        {
            s++;
            per(j,1,n) printf("%d ",p1[j]);
            printf("\n");
            return; 
        }
    }
    per(i,1,n)
    {
        if(vis[i]==0)
        {
            p[i]=x;
            vis[i]=1;
            p1[x]=i;
            fun(x+1);
            vis[i]=0;
        }
    }
}
int main()
{
    cin>>n;
    fun(1);
    if(s==0) printf("no");
    return 0;
}

总结:开学后状态太差了,开场数组开小了wa6发,题面有问题wa9发,没输出no没压缩路径wa4发,回文对称都能wa5发........

虽然会,但是实在是不能忍受,接下来找回状态好好备战区域赛。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值