新生第三次练习题解(转载)

出题人:bs, zs, ccgg
1001. bs来送签到啦
简单思考下就知道无论选择何种路线从左上角到右下角,通过平移后就等价于先向下走到底再向右走到底,所以只要两个循环累加下两条边的的价值就能得到答案(注意循环左右边界),当然也可以直接使用求和公式输出答案。
代码:

#include <stdio.h>
int main() {
    int n, m, tt;
    scanf ("%d", &tt);
    while (tt -- ){
        int n, m, ans = 0;
        scanf("%d %d", &n, &m);
        for (int i = 2; i <= n; i ++ ) ans += i;
        for (int i = 2; i <= m; i ++ ) ans += i;
        printf ("%d\n", ans);
    }
    return 0;
}

1002.大名鼎鼎的Forblue王国
本题直接暴力求出所有点的坐标之差(x,y),然后对于每个坐标(x,y)同时除以gcd(x,y),把所有处理结果存起来,去重即可。

代码:(此代码为C++代码,C语言可以用结构体写)

#include <bits/stdc++.h>

using namespace std;

int n;
vector<pair<int,int>>p,q;

int main()
{
    scanf("%d",&n);
    for(int i = 1; i <= n; i ++ )
    {
        int x, y;
        scanf("%d %d",&x,&y);
        p.push_back({x,y});
    }
    for(int i = 0; i < n; i ++ )
    {
        for(int j = 0; j < n; j ++ )
        {
            if(i != j)
                q.push_back({p[i].first - p[j].first,p[i].second - p[j].second});
        }
    }
    for(int i = 0; i < q.size(); i ++)
    {
        if(q[i].first == 0){
            if(q[i].second > 0) q[i].second = 1;
            else q[i].second = -1;
        }
        else if(q[i].second == 0){
            if(q[i].first > 0) q[i].first = 1;
            else q[i].first = -1;
        }else{
            int x = abs(__gcd(q[i].first, q[i].second));
            q[i].first /= x, q[i].second /= x;
        }
    }
    sort(q.begin(),q.end());
    q.erase(unique(q.begin(), q.end()),q.end());
    printf("%d\n",q.size());
    return 0;
}

1003.QQ飞车的大比试
题目都是一大半都是废话,输出2x - 1就行

#include <stdio.h>

int main()
{
    int t;
    scanf("%d",&t);
    while(t -- )
    {
        long long x;
        scanf("%lld",&x);
        printf("%lld\n", 2 * x  -1);
    }
    return 0;
}
  1. 简单的数组问题
    只要讨论下下出现最多的那个数的数量maxn和n的奇偶就行。
    当n为奇数,maxn小于n / 2 + 1, 答案就是1,maxn大于
    n / 2 + 1的话答案就是maxn - (maxn - n)。
    当n为偶数,maxn小于n / 2,答案就是0,maxn大于n / 2,答案就是maxn - (maxn - n)。
    代码:
#include <stdio.h>

int max(int a, int b)
{
    if(a >= b) return a;
    else return b;
}

int main()
{
    int a[100000], b[100000];
    int t;
    scanf("%d",&t);
    while(t -- )
    {
        int n;
        scanf("%d",&n);
        for(int i = 1; i <= 100000; i ++ ) b[i] = 0;
        int maxn = -1;
        for(int i = 1; i <= n; i ++ )
        {
            scanf("%d",&a[i]);
            b[a[i]] ++;
            maxn = max(maxn, b[a[i]]);
        }
        if(n % 2 == 0){
            if(maxn <= n / 2){
                printf("0\n");
            }else{
                printf("%d\n", maxn - (n - maxn));
            }
        }else{
            if(maxn <= n / 2 + 1){
                printf("1\n");
            }else{
                printf("%d\n", maxn - (n - maxn));
            }
        } 
    }
    return 0;
}
  1. bs的QQ飞车
    如果所有人在同一组里,由于每个人都可能会禁掉不同的地图,因此我们应该有n + 1张地图;
    如果每个人单独一组,则需要2张图;
    其余情况下,只需要3张地图即可满足题意。
#include <stdio.h>

int main()
{
    int t;
    scanf("%d",&t);
    while(t -- )
    {
        int n, m;
        scanf("%d %d",&n, &m);
        if(m == 1) printf("%d\n", n + 1);
        else if(n == m) printf("2\n");
        else printf("3\n");
    }
    return 0;
}

1006.bs努力不做舔狗
这道题的答案很明显,就是输出所给数中最大的那一位数字,但是注意输入的数据范围是十万位的数,用任何整数类型都存不下这样的范围,所以本题需要我们读入一个字符串来表示输入,遍历字符串中每一位得到最大值即可,注意字符型变量要在比较时转化成整型变量,另外当最大值是0时的答案是1,特判下即可。
代码:

#include <stdio.h>
#include <string.h>

int max (int a, int b) {
  if(a >= b) return a;
  else return b;
}
int main() {
    int tt;
    scanf ("%d", &tt);
    while (tt -- ) {
        int ans = -1;
        char s[100010];
        scanf ("%s", s);
        for (int i = 0; i <= strlen(s); i ++ ) ans = max (ans, s[i] - '0');
        if (ans != 0) printf ("%d\n", ans);
        else puts("1");
    }
    return 0;
}
  1. bs的数组匹配
    n是2000,本题可以先预处理出1- n中所有数的二进制,再暴力匹配,统计重合数等于k的个数就行。
#include <bits/stdc++.h>

using namespace std;

int n, k;
string a[2010];

vector<int> binary(int n)
{
    vector<int>q;
    while(n)
    {
        q.push_back(n % 2);
        n /= 2;
    }
    reverse(q.begin(),q.end());
    return q;
}

bool check(int x, int y)
{
    for(int i = 0; i + k <= a[x].length(); i ++ )
        for(int j = 0; j + k <= a[y].length(); j ++ )
            if(a[x].substr(i, k) == a[y].substr(j, k)) return true;         
    return false;
}

int main()
{
    scanf("%d %d",&n, &k);
    for(int i = 1; i <= n; i ++ )
    {
        vector<int>q = binary(i);
        for(int j = 0; j < q.size(); j ++ ) a[i] += (q[j] + '0');
    }
    int ans = 0;
    for(int i = 1; i <= n; i ++ )
        for(int j = i + 1; j <= n; j ++ )
            if(check(i, j)) ans ++;

    cout << ans << endl;
    return 0;
}

1008.wzgg的天赋
寻找最长回文子串,可以从一个回文子串中间开始往两头找,
利用循环遍历字符串数组,并以这一点为中点往两头找

#include <stdio.h>
#include <string.h>//求字符串数组长度需要strlen()函数的头文件 
int expandAround(char  str[], int left, int right)
{
    while(str[left] == str[right]  && left >= 0 && right < strlen(str))
    {
        left--;
        right++;
    }
    int s = right - left - 1;
    return s;
}
 
int max(int a, int b)//定义的函数,返回两数中的较大值 
{
    if(a > b)//如果a>b,则返回a 
        return a;
    return b;//同理返回b。注意,当a=b时,返回两者中任意一个都可,这里定义为返回b 
}
 
int main()
{
    char str[1000],c;
    int j,i,n,x;
    scanf("%d",&n);
    c = getchar();//定义的char类型的c,用来消去输入字符串前面的回车 
    for(j=0;j<n;j++) 
    {
        gets(str);
        int m = 0;
        x = strlen(str);
        for(i = 0; i <x; i++)
        {
            int len1 = expandAround(str, i, i);//长度是奇数的回文字串 
            int len2 = expandAround(str, i, i + 1);//长度是偶数的回文字串 
            int len = max(len1, len2);
            m = max(m, len);
        }
        printf("%d\n", m);
    }
    return 0;
}

1009.不难的题目
寻找最小魔王数组的大小。魔王数组的要求是对于任何一位数组的元素,他的a-1和a-2至少有一个在数组中,所以可以从1开始往上累加2,当一个数加上后总和大于等于n,将其除2即为所求。

#include <stdio.h>
int main(){
    int n,x,i,s=1,t;
    scanf("%d",&n);
    for(i=0;i<n;i++){
        scanf("%d",&x);
        s=0;
        t=1;
    while(s<x){
        s=s+t;
        t=t+2;
    }
    printf("%d\n",t/2);
    }
  return 0;
}

1010.喵喵喵?
这道题注意理解题意,并没有要求两个相等的值中间所有的值都要小于这两个值,只要保证之间的最小值小于端点值就符合条件。
令此时的n=19,当我们没有限制其他条件时,为了保证每一位的值尽可能的大,我们可以将每一位的值设为20,此时的序列为:
20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20
但由于相邻的值不能相等,所以为了满足这层条件,我们应将每两个20之间间位置先空出,此时的序列为:
20 _ 20 _ 20 _ 20 _ 20 _ 20 _ 20 _ 20 _ 20 _ 20
现在再考虑向序列中加入19,如果将剩余的每个空位都放入19的话,两个相邻的19之间的最小值会变成20,此时的序列为:
20 19 20 19 20 19 20 19 20 19 20 19 20 19 20 19 20 19 20
这样显然是不行的,所以我们需要将每两个相邻的19之间的空位放置更小的数,腾出空位后的序列:
20 19 20 _ 20 19 20 _ 20 19 20 _ 20 19 20 _ 20 19 20
现在考虑18,同19一样,两个相邻的18之间要预留一个空位:
20 19 20 18 20 19 20 _ 20 19 20 18 20 19 20 _ 20 19 20
之后17:
20 19 20 18 20 19 20 17 20 19 20 18 20 19 20 _ 20 19 20
16:
20 19 20 18 20 19 20 17 20 19 20 18 20 19 20 16 20 19 20
现在我们可以发现:
20在序列中第一次出现在20的位置上,之后每增加21的位置也是20。
19出现在21,之后每次增加22
18出现在22,之后每次增加23
17出现在23,之后每次增加24
16. .....
x 出现在2^(20 - x),之后每次增加2^(20-x+1)
于是这道题的答案已经明朗了,我们可以通过两层循环先预处理出最长的序列,之后输出长度为n的子序列即可。
代码:

#include <stdio.h>
#include <math.h>
int main() {
    const int N = 10005;
    int q[N];
    for (int i = 1; i <= 20; i ++ ) 
        for (int j = pow (2, i - 1); j <= N; j += pow (2, i) ) 
            q[j] = 20 - i + 1;
    int n;
    scanf ("%d", &n);
    for (int i = 1; i <= n; i ++ ) printf ("%d ", q[i]);
    printf ("\n");
    return 0;
}
posted @ 2022-12-02 17:29  0x3ea  阅读(22)  评论(0编辑  收藏  举报