第七次新生排位赛

第一题

时间限制 1000 ms  内存限制 65536 KB

题目描述

亲爱的小朋友们,暑假过了之后,你们要二年级啦!现在老师要检测一下你们一年级学习的读数,大家准备好自己的程序了吗?来读数吧!

 

输入格式

input
输入第一行包括一个整数t,t<=10^5,接下来t行每行有一个整数Ai,Ai<10^17

 

输出格式

output
输出每个数字的中文读法,每组数据以回车结束。为了简单起见,用阿拉伯数字0-9代替汉字零到九,用S代替十,B代替百,Q代替千,W代替万,E代替亿

 

输入样例

4
10
1101000
21000
1010010000001000

输出样例

1S
1B1SW1Q
2W1Q
1Q01SW01BE1Q

hint
10要读作一十
这题要注意,千前面是不要加0的,百,十个前面是要加的,比如一亿零五百万,一亿零五十,十亿五千万,一百亿六千

另外还有注意0的处理

机房电脑不识别%lld,要改成%I64d

注意是大写的i,I64d,不是l64d

读入可以用字符串,也可以用long long 

下面有两种代码

用字符串读取

#include <iostream>
#include <cstdio>
#include <string.h>
#include <vector>
#include <cmath>
#include <algorithm>


using namespace std;

int help, help1, help2;
int tapp;

void cal(int tag, int bt)
{
    if (bt>=1e4)
    {
        help = bt/1e4;
        cal(tag, help);
        printf("W");
        cal(4, bt%10000);
    }
    else if (bt>=1e3)
    {
        printf("%dQ", bt/1000);
        help = bt%1000;
        cal(3, help);
    }
    else if (bt>=1e2)
    {
        if ((tag == 4)||(tag==5))
            printf("0");
        printf("%dB", bt/100);
        help = bt%100;
        cal(2, help);
    }
    else if (bt>=10)
    {
        if ((tag == 3)||(tag==4)||(tag==5))
            printf("0");
        printf("%dS", bt/10);
        help = bt%10;
        cal(1, help);
    }
    else if (bt>0)
    {
        if ((tag == 3)||(tag == 2)||(tag == 4)||(tag==5))
            printf("0");
        printf("%d", bt);

    }
}

int main()
{
    int n;
    scanf("%d", &n);
    for (int i=0; i<n; i++)
    {
        char b[20], c[20];
        scanf("%s", b);
        if (strlen(b)>8)
        {
            int len = strlen(b)-9;
            for (int j=0; j<=len; j++)
                c[j] = b[j];
            
            c[len+1] = 0;
            help1 = atoi(c);
            if (help1)//这里是为了预防出现前导0的情况
            {
                cal(0, help1);
                printf("E");
            }

            for (int j=len+1; j<=len+8; j++)
                c[j-len-1] = b[j];

            c[8] = 0;
            help2 = atoi(c);
            if (help2)
                cal(5, help2);
            else if ((!help1)&&(!help2))
                printf("0");
        }
        else
        {
            help1 = atoi(b);
            if (help1)
                cal(0, help1);
            else
                printf("0");
        }
        printf("\n");
    }
    return 0;
}

用long long 读取,主函数里的处理会变得简单很多


#include <iostream>
#include <cstdio>
#include <string.h>
#include <vector>
#include <cmath>
#include <algorithm>
 
 
using namespace std;
 
long long b;
int help, help1, help2;
 
void cal(int tag, int bt)
{
    if (bt>=1e4)
    {
        help = bt/1e4;
        cal(tag, help);
        printf("W");
        cal(4, bt%10000);
    }
    else if (bt>=1e3)
    {
        printf("%dQ", bt/1000);
        help = bt%1000;
        cal(3, help);
    }
    else if (bt>=1e2)
    {
        if ((tag == 4)||(tag==5))
            printf("0");
        printf("%dB", bt/100);
        help = bt%100;
        cal(2, help);
    }
    else if (bt>=10)
    {
        if ((tag == 3)||(tag==4)||(tag==5))
            printf("0");
        printf("%dS", bt/10);
        help = bt%10;
        cal(1, help);
    }
    else if (bt>0)
    {
        if ((tag == 3)||(tag == 2)||(tag == 4)||(tag==5))
            printf("0");
        printf("%d", bt);
 
    }
}
 
int main()
{
    int n;
    scanf("%d", &n);
    for (int i=0; i<n; i++)
    {
        scanf("%lld", &b);
        if (b==0)
            printf("0");
        else if (b>=100000000)
        {
            cal(0, b/100000000);
            printf("E");
            cal(5, b%100000000);
        }
        else
            cal(0, b);
        printf("\n");
    }
    return 0;
}

第二题


时间限制 1000 ms  内存限制 65536 KB

题目描述

现有正整数集A={i|i>0&&i<=n},求A的子集合B,使得对于任意x属于B,y属于B,x整除y或y整除x。优先考虑所含元素多的子集合,然后优先考虑所含元素和大的子集合,然后优先考虑字典序小的子集合。

输入格式

每组数据包含一行一个整数n(n<1e5).输入以EOF结束。

输出格式

每组数据输出一行,从小到大输出所求集合,注意行尾不要有空格。

输入样例

6
100

输出样例

1 3 6
1 3 6 12 24 48 96
这道题分析一下是有规律的,因为要满足链最长,又要是倍数关系,对于后面的数来说,只有2倍最可靠

而前面

只有可能是1 2 4 8,或者1 3 6 12,因为1 4 8 16里面就可以加个2了


#include <iostream>
#include <cstdio>
#include <string.h>
#include <vector>
#include <cmath>
#include <algorithm>


using namespace std;

int main()
{
    int n;
    while (~scanf("%d", &n))
    {
        int ans = -1;
        int t = n;
        while (t>0)
        {
            ans++;
            t = t>>1;
        }
        printf("1");
        int tl;
        if (((1<<(ans-1))*3) <= n) // 2 的(ans-1)次方乘以3小于等于n
            tl = 3;
        else
            tl = 2;
        for (int i=0; i<=ans-1; i++)
        {
            printf(" %d", tl);
            tl *= 2;
        }
        cout << endl;
    }

    return 0;
}

第三题

时间限制 1000 ms  内存限制 65536 KB

题目描述

有一个传说,对给定正整数 m 和 q,总有一个边长为 a,b,c 的三角形,是满足 a % m + b % m = c % m = q 的条件的三角形中周长最小的。
Mays 对此深信不疑,她打算和你一起探讨这个问题。她出了一些数据,请你帮忙求最小周长,如果找不到这样一个三角形,也请你告诉她这个惨痛的事实。

输入格式

给一个组数 T。接下来 T 组,每组两个数字 m 和 q ,(1 <= m <= 10^5 , 0 <= q < m)。

输出格式

输出当前组数和最小周长,格式见样例。若不存在满足的三角形,请把最小周长的数字替换成"Poor Mays!".

输入样例

2
3 2
3 2

输出样例

Case 1: 7
Case 2: 7
这道题分四种情况讨论,因为分类并不多,其实算法倒没有什么,主要是思想吧


#include <iostream>
#include <cstdio>
#include <string.h>
#include <vector>
#include <cmath>
#include <algorithm>
 
 
using namespace std;
 
int main()
{
    int t;
    scanf("%d", &t);
    for (int i=1; i<=t; i++)
    {
        int m, q;
        scanf("%d %d", &m, &q);
 
        if (q==0)
            printf("Case %d: %d\n", i, 3*m);
        else if (2*q > m)
            printf("Case %d: %d\n", i, 2*q+m);
        else if (q==1)
            printf("Case %d: %d\n", i, 3*m+2*q);
        else
            printf("Case %d: %d\n", i, 2*m+2*q);
    }
 
    return 0;
}

第四题

这题有两种方法,规范的话用spfa,其实我真没弄明白这个和迪杰斯特拉到底什么区别

另一种直接来回松弛(可能是题目并不复杂吧)

来回松弛法

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>
 
using namespace std;
int a[10005]; // 存起点到该传送门最短距离
int b[10005]; // 该传送门到终点最短距离
 
int main()
{
    int n, m;
    scanf("%d %d", &n, &m);
    while (n&&m)
    {
        int temp;
        for (int i=1; i<=n; i++)
        {
            scanf("%d", &temp);
            a[i] = i+temp-2;
            b[i] = n+m-temp-i;
 
        }
        for (int i=2; i<=n; i++)// 顺着松弛一遍
        {
            a[i] = min(a[i], a[i-1]+1);
            b[i] = min(b[i], b[i-1]+1);
        }
        for (int i=n-1; i>0; i--)// 反着松弛一遍
        {
            a[i] = min(a[i], a[i+1]+1);
            b[i] = min(b[i], b[i+1]+1);
        }
        int sum = m+n-2; // 这个是最大体力消耗了了,不管过不过传送门
        for (int i=1; i<=n; i++)
        {
            sum = min(sum, a[i]+b[i]); // a[i]+b[i]是假如过这个传送门最少体力消耗
        }
        printf("%d\n", sum);
 
        scanf("%d %d", &n, &m);
    }
    return 0;
 
}

spfa + 手写链表     hullabaloo的代码

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
#include<cstring>
#define SIZE_X 10010
#define INF 100000000
using namespace std;
int a[SIZE_X];
struct pre
{
    int v,next,cost;
}pic[SIZE_X*4];
int e,head[SIZE_X*4];
bool vis[SIZE_X];
int d[SIZE_X];
void init()
{
    e=0;
    memset(head,-1,sizeof(head));
}
void savepic(int x,int y,int z)
{
    pic[e].v=y;
    pic[e].cost=z;
    pic[e].next=head[x];
    head[x]=e++;
}
int n,m;
int spfa(int st,int ed)
{
    for(int i=0;i<=n+1;i++)
    {
        d[i]=INF;
        vis[i]=0;
    }
    queue<int>que;
    d[st]=0;
    while(!que.empty())que.pop();
    que.push(st);
    while(!que.empty())
    {
        int v=que.front();
        que.pop();
        for(int i=head[v];i!=-1;i=pic[i].next)
        {
            int u=pic[i].v,w=pic[i].cost;
            if(d[u]>d[v]+w)
            {
                d[u]=d[v]+w;
                if(!vis[u]){que.push(u);vis[u]=1;}
            }
        }
        vis[v]=0;
    }
    return d[ed];
}
int main()
{

    while(~scanf("%d %d",&n,&m))
    {
        if(n==0&&m==0)
            break;
        init();
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            savepic(0,i,((m-a[i])+(n-i)));
            savepic(i,n+1,((a[i]-1)+(i-1)));
            if(i!=1)
                savepic(i,i-1,1);
            if(i!=n)
                savepic(i,i+1,1);
        }
        printf("%d\n",spfa(0,n+1));
    }
}

第五题 正在研究中。。。。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值