吉首大学第八届“新星杯”大学生程序设计大赛部分解题报告

 

问题 A: 组合数 

题目描述

求组合数C(N,M),以及C(N,M)因子个数。

输入

N和M,其中0<=M<=N<=50,以EOF结束。

输出

该组合数结果

样例输入 Copy

3 2
4 2

样例输出 Copy

3 2
6 4

思路: 1.C(N,M) (0<=M<=N<=50)可以选择打表

         2.由于数据较大,普通的求因子个数算法肯定超时,这时可以考虑质因子分解算法求因子个数

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
using namespace std;
const int Max=60;
typedef long long LL;
LL C[Max][Max];
void Init()
{
    for(int i=0;i<=50;i++)
    {
        C[0][i]=0;
        C[i][0]=1;
    }
    for(int i=1;i<=50;i++)
    {
        for(int c=1;c<=50;c++)
        {
            C[i][c]=C[i-1][c]+C[i-1][c-1];
        }
    }
    return ;
}
int factor(LL x)
{
    int n=1;
    for(LL i=2;i<=x;i++)
    {
        if(x%i==0)
        {
            int c=0;
            while(x%i==0)
            {
                x/=i;
                c+=1;
            }
            n*=(1+c);
        }
        if(x<i) break;
    }
    return n;
}
int main()
{
    int N,M;
    Init();
    while(~scanf("%d %d",&N,&M))
    {
        printf("%lld %d\n",C[N][M],factor(C[N][M]));
    }
    return 0;
}

问题 C: 序列交换

题目描述

给一个 1 到 n 的排列,每次可以交换相邻两个数,问使用最少操作次数使得序列递增的方案是否唯一。 

输入

多组输入,每组一个数n(1<=n<=10^5),然后是一个1~n的排列。

输出

方案唯一输出Yes,否则输出No。

样例输入 

1
2
2 1
3
3 2 1

样例输出

Yes
No

思路:题目所问的是否存在唯一的最少操作次数方案 ,其实可以发现只要对一个序列操作次数>=2时便不存在唯一情况

        再转换一下,若序列存在一个最长递增子序列且长度>=N-1时,是符合要求的

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
const int Max=1e5+5;
vector<int> v;
int main()
{
    int N,Arr[Max];
    while(~scanf("%d",&N))
    {
        for(int i=0;i<N;i++){
            scanf("%d",&Arr[i]);
        }
        for(int i=0;i<N;i++){
            if(v.empty()||Arr[i]>v[v.size()-1])
                v.push_back(Arr[i]);
            else
            {
                int index=upper_bound(v.begin(),v.end(),Arr[i])-v.begin();
                v[index]=Arr[i];
            }
        }
        if(v.size()>=N-1)
            printf("Yes\n");
        else
            printf("No\n");
        v.clear();
    }
    return 0;
}

问题 E: Jack的A+B

题目描述

现在有整数a,b,请按西方数字数量级方式输出a+b

输入

题目有多组测试数据
每组输入两个整数a,b
(0<=a,b<=10000000)

输出

输出西方数字数量级的a+b

样例输入 Copy

999 1
36 30
100000 100

样例输出 Copy

1,000
66
100,100

提示

输出的数从最低位起,每三位用逗号隔开

思路: 唯一的问题就是控制符号','的输出,找一下规律就好了

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<set>
#include<map>
#include<cmath>
using namespace std;
typedef long long LL;
int main()
{
    int x,y,z,n;
    while(~scanf("%d %d",&x,&y))
    {
        z=x+y;
        if(z==0)
        {
            printf("0\n");
            continue;
        }
        char str[20];
        n=0;
        while(z)
        {
            str[n]=z%10+'0';
            z/=10;
            n+=1;
        }
        str[n]='\0';
        int Tag=1;
        for(int i=n-1;i>=0;i--)
        {
            printf("%c",str[i]);
            if(i!=0&&(n-Tag)%3==0)
                printf(",");
            Tag+=1;
        }
        printf("\n");
    }
    return 0;
}

问题 G: 圆桌上的晚餐

题目描述

        大家一定在圆桌上吃过饭了,现在问题很简单,n个人坐在一个圆桌旁,其中有一些人是吃饱了的。那么当服务员端菜到某个人面前的时候,如果这个人吃饱了的话,那么这个人就会进行‘战术谦让’把菜端到下一个人的面前,如此反复直到这个菜遇到还没有吃饱的人的面前的时候,这个菜就会被吃掉。那么这个菜到底会被哪个人吃掉呢。

输入

 输入有多组数据 每组数据第一行有一个n,表示有n个人(1<= n <=1000)
 第二行有一个m表示菜会被端到第m个人面前(1<= m <= n)
 第三行有n个数字表示每个人的状态0表示还没有吃饱,1表示已经吃饱了
 (编号从1开始,第n个人下一个人是第一个人)

输出

    输出最终吃掉这个菜的人的编号答案一定存在

样例输入 Copy

5 
5
0 0 0 0 1
5 
3
1 0 1 1 1

样例输出 Copy

1
2

思路: 循环找0

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<set>
#include<map>
#include<cmath>
using namespace std;
typedef long long LL;
int main()
{
    int N,M,p[1005];
    while(~scanf("%d %d",&N,&M))
    {
        for(int i=1;i<=N;i++){
            scanf("%d",&p[i]);
        }
        while(p[M]!=0)
        {
            M+=1;
            if(M>N)
                M-=N;
        }
        printf("%d\n",M);
    }
    return 0;
}

问题 I: 夫子云游

题目描述

 改编自猫腻所著的同名小说《将夜》目前正在火热开播,其中男主角宁缺在考书院二层楼时遇一题“那年春,夫子出国游历,遇桃山美酒,遂寻径登山赏桃品酒,一路摘花饮酒而行,始斩一斤桃花,饮一壶酒,后夫子惜酒,故再斩一斤桃花,只饮半壶酒,再斩一斤桃花,饮半半壶酒,如是而行……至山顶,夫子囊中酒尽,惘然四顾,问:夫子一共斩了几斤桃花,饮了几壶酒?”而当我们的男主角宁缺看到这道题目时,更是直接来了句“谁出的这道题,太二了”,紧接着就提笔写下了“夫子饮二壶酒,斩尽满山桃花”后直接就交卷走人了赢得书院弟子的大赞。

今夫子再次游历,他提着酒壶,从出院出来,酒壶中有酒2斗,他边走边唱:

    无事街上走,提壶去打酒。
    逢店加一倍,遇花喝一斗。

这一路上,他一共遇到店M(0<M<=10)次,遇到花N(0<M<=10)次,已知最后一次遇到的是花,他正好把酒喝光了。

请计算夫子遇到店和花的合理的次序种数。

可以把遇店记为a,遇花记为b,如果M=5,N=10。则:babaabbabbabbbb 就是合理的次序之一。

输入

M、N 分别为遇到店和花的次数

输出

所有可能店和花次序方案的个数

样例输入 Copy

5 10

样例输出 Copy

14

思路:DFS找合理次序,每次搜索无非两种情况 1.遇店 2.遇花 

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<set>
#include<map>
#include<cmath>
using namespace std;
int M,N,re;
void DFS(int x,int y,int z)
{
    if(x<=0||x>z)
        return ;
    if(x==1)
    {
        if(y==0&&z==1)
        {
            re+=1;
            return ;
        }
    }
    DFS(x-1,y,z-1);
    DFS(2*x,y-1,z);
    return ;
}
int main()
{
    while(~scanf("%d %d",&M,&N))
    {
        re=0;
        DFS(2,M,N);
        printf("%d\n",re);
    }
    return 0;
}

问题 J: 老肖数等式

题目描述

老肖前几年当了小学数学老师,他每天都会布置一次题目,他布置题目有个习惯,他只布置两个数的加法,两个数都不超过100,而且会让所有的题目答案都是一样的,所以这真的是一个奇怪的数学老师呢,他又有点想偷点懒,想你帮他做个自动出试卷的程序,你能帮他解决这个问题吗?

输入

多组输入,每行输入一个数x作为等式答案(0<=x<=200)

输出

每行输出一个等式,等式里的两个数a,b(0<=a,b<=100)

样例输入 Copy

5
3

样例输出 Copy

1. 0+5=
2. 1+4=
3. 2+3=
1. 0+3=
2. 1+2=

思路:唯一要注意的就是已出现过的a,b不会再以b,a的形式出现

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<set>
#include<map>
#include<cmath>
using namespace std;
typedef long long LL;
int main()
{
    int x;
    while(~scanf("%d",&x))
    {
        for(int i=0;i<=x/2;i++)
        {
            printf("%d. %d+%d=\n",i+1,i,x-i);
        }
    }
    return 0;
}

问题 K: WaWa的难题

题目描述

HaHa和WaWa是好朋友,他们在临近期末的这段时间一起宅在图书馆学习。
今天HaHa在书上看到一个排列组合题目,思考很久后,仍然找不出其中的规律。
于是他把题目叙述给了WaWa。
题目:
————————————————————————
一个长度为N的排列,由数字1~N组成,它满足两个条件。
1、数字1永远在第一位。
2、任意两个相邻数字之差小于等于2。
现在给出一个N,
你能知道能组成多少个符合条件的排列吗?。
例如:
N=4
1 2 3 4
1 2 4 3
1 3 2 4
1 3 4 2
所以答案为4
————————————————————————
WaWa听后也是一脸懵逼。
现在WaWa想求助于你们,WaWa给出一个正整数N,问你用1~N能组成多少个符合题意的排列。

输入

多组数据。
每组数据输入一个正整数N(1<=N<=100)。

输出

输出符合题意的排列个数

样例输入 Copy

2
4

样例输出 Copy

1
4

思路:通过DFS找出N=i(i<=12)的次序数,然后就是艰难的找规律过程

        规律:N[i]=N[i-1]+N[i-3]+1

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<set>
#include<map>
#include<cmath>
using namespace std;
typedef long long LL;
LL Arr[200]={0,1,1,2,4,6,9};
void Deal()
{
    for(int i=7;i<=100;i++)
    {
        Arr[i]=Arr[i-3]+Arr[i-1]+1;
    }
}
int main()
{
    int N;
    Deal();
    while(~scanf("%d",&N))
    {
        printf("%lld\n",Arr[N]);
    }
    return 0;
}

问题 M: 最亲密的x个人 

题目描述

有一天,地球受到了降维打击,从三维变成了一维。从此我们都生活在一条线上,给这条线加上坐标,每个点都是大于等于 0 的正整数。

有一天小明突发奇想,想知道谁是他最亲密的人,距离小明越近的人和小明越亲密。

假设有 N 个人,每个人的编号为 i(1 <= i <= N ),坐标为 ki(k[i-1] <= k[i] <= k[i+1]),小明的坐标为 M(小明是 N 个人中的一个),你们可以帮助小明找到他最亲密的 X个人的编号吗?

输入

多组输入 
对于每组数据,第一行为三个整数N(0<N<=100000 )、M(0<M<=100000000)、X(X <= N && X <= 100)
第二行有N个数,分别表示 N 个人的坐标 

输出

小明最亲密的 X 个人的编号(亲密度相同的,按id从小到大输出。如果第 x+1 个人和第 x 个人一样亲密,也需要输出)

样例输入 Copy

3 2 1
1 2 4
3 2 1
1 2 3

样例输出 Copy

1
1
3

思路:按亲密度排序

        注意一种情况:如果第 x+1 个人和第 x 个人一样亲密,也需要输出

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
using namespace std;
const int Max=1e5+5;
struct node{
  int x;
  int y;
  int z;
}c[Max];
bool Compare(node u,node v)
{
    if(u.z==v.z)
        return u.y<v.y;
    return u.z<v.z;
}
int main()
{
    int N,M,X;
    while(~scanf("%d %d %d",&N,&M,&X))
    {
        for(int i=1;i<=N;i++)
        {
            scanf("%d",&c[i].x); //坐标
            c[i].y=i;            //编号
            c[i].z=fabs(M-c[i].x); //亲密度
        }
        sort(c+1,c+N+1,Compare);
        for(int i=2;i<=X+1;i++)
        {
            printf("%d\n",c[i].y);
        }
        if(c[X+1].z==c[X+2].z)
            printf("%d\n",c[X+2].y);
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ZCMU_2024/article/details/85287270