牛客竞赛语法入门班循环结构习题

1018 有趣的二进制

题目描述:
一个数在64位二进制补码表示下,一共有多少个1。因为小数有无解的情况,所以我们保证输入的都是整数。

输入描述:
有多组数据,每一行为一个数字n。

输出描述:
输出这个数字在二进制补码下1的个数。

示例:
输入
15
输出
4

AC代码:

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
#define int unsigned long long 
signed main()
{
    int n;
    while (scanf("%llu", &n) != EOF)
    {
        int count = 0;
        if (n >= 0)
        {
            while (n != 0)
            {
                if (n % 2 != 0)
                    count++;
                n /= 2;
            }
        }
        else
        {
            n = -n;
            if (n % 2 != 0)
                count--;
            while (n != 0)
            {
                if (n % 2 != 0)
                    count++;
                n /= 2;
            }
            count = 64 - count;
        }
        cout << count<<endl;
    }
    return 0;
}

备注:
此题还不会,种草,到时候填坑。(好像说什么unsigned long long 就是这个数二进制补码,不明白,不清楚)

1019 [NOIP2006]数列

题目描述:
给定一个正整数k( 3 ≤ k ≤ 15 ),把所有k的方幂及所有有限个互不相等的k的方幂之和构成一个递增的序列,例如,当k = 3时,这个序列是:
1,3,4,9,10,12,13,…(该序列实际上就是:30,31,30+31,32,30+32,31+32,30+31+32,…)
请你求出这个序列的第N项的值(用10进制数表示)。例如,对于k = 3,N = 100,正确答案应该是 981。

输入描述:
输入1行,为2个正整数,用一个空格隔开:k N(k、N的含义与上述的问题描述一致,且3 ≤ k ≤ 15,10 ≤ N ≤ 1000 )。

输出描述:
输出一个正整数(在所有的测试数据中,结果均不超过2.1*109)。(整数前不要有空格和其他符号)

示例:
输入
3 100
输出
981

分析:
此题有两个方法可以解,先讲最直接的暴力(居然没有TLE)

法一(暴力):
发现
a[0]=1
a[1]=3 a[2]=4
a[3]=9 a[4]=10 a[5]=12 a[6]=13
a[7]=27 a[8]=28......
可以先分组,设下标为i,当i+1是2的x次方是分新的一组,每一组的个数为1,2,4,8......并且可以发现每组的开头是3的x次方,剩下的每组为每组开头依次加上前面各组的值,即a[4]=a[3]+a[0], a[5]=a[3]+a[1], a[6]=a[3]+a[2]

AC代码:

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
#define int long long 
signed main()
{
    int sum = 0;
    vector<int>vet(1100);
    vet[0] = 1;
    int a,b;
    cin >> b>>a;
    if ((int)(log(a) / log(2)) == log(a) / log(2))
        cout << pow(b, log(a) / log(2));
    else
    {
        int m = (int)(log(a) / log(2));
        int n = a - (int)pow(2, m);
        sum = (int)pow(b, m);
        n--;
        int k = 0;
        for (int i = 1; i <= n; i++)
        {
            if ((int)(log(i + 1) / log(2)) == log(i + 1) / log(2))
            {
                vet[i] = (int)pow(b, (log(i + 1) / log(2)));
                k = i;
            }
            else
                vet[i] = vet[k] + vet[i - 1 - k];
        }
        sum += vet[n];
        cout << sum;
    }
    return 0;
}

 法二:

 可观察出规律,其实从上到下是二进制的1 2 3 4 5.....故易得答案,只用判断数字的位次在二进制下每一位为1还是0即可(用位运算&和>>)是1,则加上对应的次方,若是0则继续判断。

AC代码:

#include<bits/stdc++.h>
 
using namespace std;
#define int long long
signed main()
{
    int k,N;
    cin>>k>>N;
    int ans=0;
    int i=0;
    while(N)
    {
        if(N&1)
        {
            ans+=pow(k,i);
            
        }
         N=N>>1;
        i++;
    }
    cout<<ans;
    return 0;
}

1026 栗酱的文明2

题目描述:
已知游戏结束前场上有n个国家,第i个国家有ai块土地,任意2个国家若是想建立外交关系,则需要互相在对方的一块土地上建立一个大使馆。
一块土地只能建立一个大使馆,若一个国家和其他国家存在外交关系,则需要征用一块己方土地作为备用大使馆。
完美结局的定义是:找到最多数量的国家,使他们相互之间存在外交关系。

输入描述:
第一行一个数T,表示有T组数据。
对于每组数据,第一行输入一个数n,表示国家的数量,接下来一行输入n个数,a1,a2,…,an,其中ai表示第i个国家拥有的土地数量。每两个相邻的数之间用空格隔开。

输出描述:
对于每一个询问,输出一个数,即完美结局下,相互建立外交关系的国家数量。

示例:
输入
2
5
2 2 2 2 2
10
8 6 5 9 2 7 10 3 3 9
输出
2
6

备注:
T≤10
1≤n≤1000
1≤ai≤n

分析:
出题人问斩!!!!其实题目的意思就是若有n个国家相互之间存在外交关系,那么拥有土地最小的国家至少有n块土地。所以只需要sort排序,什么时候数列中的数字小于其下标+1(下标+1代表着有几个国家有外交关系),此时下标+1就为最终答案(e.g 9 7 4 3 1 1,那么当下标为2时,为最大的符合条件的下标,那么最终答案为3)

AC代码:

#include<bits/stdc++.h>

using namespace std;
int a[1010];
bool cmp(int a,int b)
{
    if(a>b)
        return 1;
    return 0; 
}
int main()
{
    int T;
    cin>>T;
    for(int i=0;i<T;i++)
    {
        int n;
        cin>>n;
        for(int k=0;k<n;k++)
            cin>>a[k];
        sort(a,a+n,cmp);
        int k;
        for(k=0;k<n;k++)
        {
            if(a[k]<k+1)
                break;
        }
        cout<<k<<endl;
    }
    return 0;
}

 备注:
做题时完全没有没有思路,甚至把“一块土地上只能建立一个大使馆”这个条件理解错了,稀里糊涂理解成一个国家只能和一个国家建交(樂)

1028 [NOIP2000]进制转换

题目描述:
即把一个数变为负进制数,且用A表示10,B表示11,以此类推。其中负进制数的基数-R从-2到-20(题面太长,但就是这个意思)

输入描述:
第一个是十进制数N(-32768 ≤ N ≤ 32767);  第二个是负进制数的基数-R。

输出描述:
输出此负进制数及其基数,若此基数超过10,则参照16进制的方式处理。

示例:
输入
30000 -2
输出
30000=11011010101110000(base-2)
输入
-25000 -16
输出
-25000=7FB8(base-16)

分析:
此题的难点主要在于如何将一个数转换成负进制数,我们知道将一个数转换成一个正整数进制数的方法是将原数一直除以正整数进制数的基数并将余数倒序输出,但若是负进制数则会面临余数是负数的情况,此时难以处理。我们知道   被除数=商*除数+余数  所以当余数是负数时,我们让商加一,余数减去除数,余数则变为正(被除数=(商+1)*除数+余数-除数)此题便迎刃而解了。

:不要忘记0的处理!!!!!

AC代码:

#include<bits/stdc++.h>
 
using namespace std;
 
signed main()
{
    int N, R;
    cin >> N >> R;
    char a[1000];
    int i = 0;
    int m = N;
    while (N)
    {
        int b;
        int flag=0;
        b = N % R;
        if (b < 0)
        {
            b = b - R;
            flag=1;
        }
        if (b > 9)
        {
            b = b - 10 + 'A';  
        }
        else
        {
            b = b + '0';
        }
        N=N/R+flag;
        a[i++] = b;
    }
    a[i] = '\0';
    int len = strlen(a);
    cout << m << "=";
    if(len==0)
        cout<<0;
    else
         for (int i = len - 1; i >= 0; i--)
             printf("%c", a[i]);
    printf("(base%d)", R);
    return 0;
}


1030 Game

题目描述:
Nancy喜欢博弈!
Johnson和Nancy得到了一个神奇的多重集合,仅包含一个正整数n,两个人轮流进行操作。
一次操作可以将集合中一个数字分解为它的任意两个非1的因数,并加入集合中。
他们想知道,在Johnson和Nancy绝顶聪明的情况下,如果Nancy先手进行操作,最后谁没有办法继续操作了呢?

输入描述
第一行:一个整数n。
数据满足:1≤n≤95718

输出描述:
共一行:一个字符串,表示最后谁(Johnson或者Nancy)无法进行操作

示例:
输入
4
输出
Johnson

分析:
博弈问题。实为分析一个合数由多少个素数组成,求得素数的个数即可。(一个合数一定可以分解成有限个素数的乘积(唯一分解定理)) 若一个数能拆分成5个素数,则一共只能进行4轮(第一轮拆成2个素数,第二轮3个,以此类推) 分奇偶讨论。

AC代码:

#define _CRT_SECURE_NO_WARNINGS
#include<bits/stdc++.h>
using namespace std;
signed main()
{
    int count = 0;
    int n;
    cin >> n;
    for(int i=2;i*i<=n;i++)
    {
        while(n%i==0)
        {
            count++;
            n/=i;
        }
    }
    if(n!=1)
        count++;
    if(count%2==0)
        cout<<"Johnson";
    else
        cout<<"Nancy";
    return 0;
}

 代码解释:
原理应该是除下一个素数,但为了写代码方便,可直接除以下一个数,因为若遇到合数也除不尽(在之前已经除完其因数)其中if(n!=1)的判断是为了判断在大于根号n的时候是否仍有一个素数(最多有一个),当n为1时则没有,若n不等于1,那么就为其本身(e.g 14可分解为2和7,当除以2时,n=7,因此count+1)

备注:
在做题的时候没有考虑到i<sqrt(n)时还有一个本身为其因数。QAQ......

1031 [NOIP1999]Cantor表

题目描述:
现代数学的著名证明之一是Georg Cantor证明了有理数是可枚举的。他是用下面这一张表来证明这一命题的:

  我们以Z字形给上表的每一项编号。第一项是1/1,然后是1/2,2/1,3/1,2/2,…

输入描述:
整数N(1≤N≤10000000)

输出描述:
表中的第N项

示例:
输入
7
输出
1/4

分析:
分析图得规律,不妨设1/1为第一个斜线,1/2,2/1为第二个斜线,易看出第n个斜线有n个数字,其中当n为偶数时,从1/n开始,每往下一个,分子加1,分母减1;当n为奇数时,从n/1开始,每往下一个,分子减1,分母加1;则只用判断所求N离最近的的斜线相差几,便可求出第N项为多少。

AC代码:

#include<bits/stdc++.h>
using namespace std;
signed main()
{
    int N,a,b;
    cin>>N;
    int n=0;
    while(n*(n-1)/2+1<=N)
        n++;
    n--;
    int count=N-n*(n-1)/2-1;
    if(n%2==0)
    {
        a=1+count;
        b=n-count;
    }
    else
    {
        a=n-count;
        b=1+count;
    }
    cout<<a<<"/"<<b;
    return 0;
}

代码解释:
其中n*(n-1)/2+1,要加1是为了使初始位置在斜线的第一个数字,而不是最后一个数字(对于我而言思考会更加方便)。

备注:
做题时完全没有看出这条规律Orz

1037 焦虑的蚂蚁

题目描述:
一条长度为n的小径上,挤满了m只蚂蚁,每只蚂蚁有一个初始前进方向(向左或是向右),蚂蚁们的前进速度相同且均为1。小径的两端,均放着上了锁的箱子,箱内盛有美味的食物,蚂蚁们争相前进离开小径。不幸的是,小径十分狭窄,当两只蚂蚁相遇时,它们不得不掉头向着相反的方向前进。当所有的蚂蚁都离开小径时,锁才能够打开,蚂蚁们才能获得美味的食物。因此,蚂蚁们十分焦虑,它们想知道,到底花费多少的时间,它们才能够吃到美味的食物。你能够帮助他们解决问题吗?

输入描述:
第一行,2个整数n,m(1≤m<n≤100000,n,m均为整数),分别代表小径的长度,蚂蚁的数量。
接下来m行,每行2个数,分别代表蚂蚁的初始方向(0代表向左,1代表向右),蚂蚁的初始坐标x满足x为整数且0<x<n,蚂蚁走到坐标0或坐标n即代表离开小径。
数据保证每个坐标上最多有1只蚂蚁。数据保证给出的蚂蚁初始坐标为从小到大。

输出描述:
一行,对结果四舍五入,输出一个整数,代表蚂蚁吃到美味的食物的时间。

示例:
输入:
50 10
1 6
0 15
0 19
1 20
0 22
0 25
1 36
0 39
1 40
1 42
输出:
44

分析:
看似蚂蚁掉头很麻烦,其实可以看做成两只蚂蚁做了交换,即两只蚂蚁并没有掉头,只是灵魂互换了(魂穿bushi)所以蚂蚁一直都在向前走,没有掉头,那么题目就变成了求蚂蚁从起始位置走向终点的最久时间。

AC代码:

#include <bits/stdc++.h>
 
using namespace std;
signed main()
{
    int n,m;
    cin>>n>>m;
    int maxn=0;
    for(int i=0;i<m;i++)
    {
        int a,b;
        cin>>a>>b;
        if(a==1)
            b=n-b;
        maxn=max(maxn,b);
    }
    cout<<maxn<<endl;
    return 0;
}


1046 鹏

题目描述:
HtBest的小鲲长大变成了大鹏,大鹏在天际翱翔,看到了一片绵延的山脉,每座山都有自己的高度,大鹏想穿过这片山脉。由于他只能紧贴地面飞行,他想知道他一共要翻越几次大山(上升->平飞->下降,算一次,其中平飞可以没有),初始时,大鹏在山脉的左端。

输入描述:
第一行一个正整数n,表示山脉被分为n段。
第二行有n个正整数ai两两之间用空格分开,ai表示山脉第i段的高度。

输出描述:
一行,包含一个正整数,表示大鹏需要翻越几次大山。

示例:
输入:
3
1 2 1 
输出:
1
输入:
3
3 1 2
输出:
0

分析:
暴力就行,用一个数组存输入的数字,然后比较三个数,若中间的数和右边的数相等,那么右边的数右移,直到两数字不相等再进行比较。

AC代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long 
signed main()
{
    int n;
    cin>>n;
    int count =0;
    vector<int>vec(n);
    for(int i=0;i<n;i++)
    {
        scanf("%d",&vec[i]);
    }
    for(int i=1;i<n-1;i++)
    {
        int a=i-1,b=i+1;
        while(vec[i]==vec[b]&&b!=n)
            b++;
        if(vec[i]>vec[a]&&vec[i]>vec[b])
            count++;
    }
    cout<<count;
    return 0;
}

备注:
当时一直WA,是因为让左边端点也移动了,这会导致有些上升会算重复(e.g 2 5 5 5 5 5 5 5 1 会被算成7次,所以只有动右边就行)

1050 回文对称数

题目描述:
回文数是正着读与倒着读都一样的数,比如1221,343是回文数,433不是回文数。请输出不超过n的回文数。

输入描述:
输入一个整数n(1 <= n <= 100000)

输出描述:
从1开始按从小到大的顺序输出所有回文数

示例:
输入:
10
输出:
1
2
3
4
5
6
7
8
9

分析:
此题主要考察回文数如何判断。可以定义一个新的数,并且将输入的数的倒序存入此数中,比较两数是否相同。

AC代码:

#include<bits/stdc++.h>
 
using namespace std;
 
int main()
{
    int n;
    cin>>n;
    for(int i=1;i<n;i++)
    {
        int a=i;
        int ans=0;
        while(a)
        {
            ans*=10;
            ans+=a%10;
            a/=10;
        }
        if(ans==i)
            cout<<i<<endl;
    }
    return 0;
}

  • 33
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值