CCNU ACM 2016夏季集训·day1比赛

表示这比赛坑好多……

题目页面

咳,总之在各种特殊的wa姿势之间摸爬滚打终于完成了这8道题……
题解时间到~


A 最小公倍数

a1 , a2 ,…, an 共n个数的最小公倍数。

关键:若x是 a1 , a2 ,…, an1 的最小公倍数,则 a1 , ,a2 ,…, an 的最小公倍数为 anxgcd(x,an) (注意实际实现中先除后乘,否则有可能爆范围)。

#include <cstdio>

using namespace std;

typedef unsigned int u32;

u32 gcd(u32 a,u32 b){return b?gcd(b,a%b):a;}

int main(){
    int t,n;
    u32 tmp,ans;
    int i,j;

    scanf("%d",&t);
    for(i=0;i<t;i++){
        scanf("%d",&n);
        ans=1;
        for(j=0;j<n;j++){
            scanf("%u",&tmp);
            ans*=tmp/gcd(ans,tmp);
        }
        printf("%u\n",ans);
    }
    return 0;
}

B 进制转换

输入一个十进制整数n,输出它的r进制表示形式。

解法:连除取余,倒序输出。
原理: n=a0r0+a1r1+a2r2+...+anrn
技巧:此题输入有多组数据,且题目未给出数据组数,开始我用feof(stdin)来判断是否已读到文件末尾,但貌似在win下不灵(渣渣ms还我罚时!)……最后在出题人主办方建议下改成了scanf(...)==EOF来判断……
注意:有负数,而且至少在我见过的代码中输入为0的情况都要特判。

#include <cstdio>

typedef long long ll;

char str[64];

int main(){
    ll n;
    int r;
    int i;

    while(!feof(stdin)){
        scanf("%I64d%d",&n,&r);
        if(n==0)printf("0\n");
        else{
            if(n<0){
                putchar('-');
                n=-n;
            }
            for(i=0;n;i++){
                str[i]=n%r;
                n/=r;
            }
            for(i--;i>=0;i--)
                putchar((str[i]>9)?(str[i]-10+'A'):str[i]+'0');
            putchar('\n');
        }
    }
    return 0;
}

C 三角形

输入三个正数问能否以这三个数为三边长组成三角形。

知识:小学算术。

#include <cstdio>
#include <algorithm>

using namespace std;

double l[3];

int main(){
    int m;
    int i,j;

    scanf("%d",&m);
    for(i=0;i<m;i++){
        for(j=0;j<3;j++)
            scanf("%lf",l+j);
        sort(l,l+3);
        printf((l[0]+l[1]>l[2])?"YES\n":"NO\n");
    }
    return 0;
}

D 空心三角形

输入一个三角形的高,在输出中绘制出这个三角形。

经验:一个高为 h 的三角形底边长为2n1
(不是很复杂的实现题我一般不会出问题……)

#include <cstdio>

using namespace std;

char str[10];

int main(){
    int n;
    bool b=false;
    char c;
    int i,j;

    while(true){
        scanf("%s",str);
        c=str[0];
        if(c=='@')break;
        if(b)putchar('\n');
        scanf("%d",&n);
        for(i=1;i<=n;i++){
            for(j=i;j<n;j++)putchar(' ');
            putchar(c);
            if(i==1){
                putchar('\n');
            }else if(i==n){
                for(j=2;j<n*2;j++)putchar(c);
                putchar('\n');
            }else{
                for(j=3;j<i*2;j++)putchar(' ');
                putchar(c);
                putchar('\n');
            }
        }
        b=true;
    }
    return 0;
}

E 整数解

输入两个整数n和m,问方程组

{x+y=nx×y=m

是否至少有一组整数解……

解法1:枚举 x[|m|,|m|] ,则 y=nx ,判断 xy=m 是否成立即可。
解法2:

xy=m

y=mx

代入 x+y=n 中得
x+mx=n

x2nx+m=0

然后利用一元二次方程求根公式即可。(正在码……)

注意:”Yes”和”No”!

#include <cstdio>
#include <cmath>

using namespace std;

int main(){
    int n,m;
    int absm;
    bool b;
    int i;

    while(true){
        scanf("%d%d",&n,&m);
        if((!n)&&(!m))return 0;
        b=false;
        absm=abs(m);
        for(i=-absm;i<=absm;i++){
            if(abs(n-i)>absm)continue;
            if(i*(n-i)==m){
                printf("Yes\n");
                b=true;
                break;
            }
        }
        if(!b)printf("No\n");
    }
    return 0;
}

F 考试排名

典型毒瘤手写ms word题……(出题人呢?出来出来……)

技巧:scanf()返回值为成功输入的数据个数(,然后你就知道括号怎么办了吧……)
注意:排序先按ac数降序,ac数相同再按时间分升序,都相同再按名字字典序升序……(大于小于别搞反)

吐槽:你妹滴题目明明没有说明最大学生数量,害我wa了四次!(出题人还我罚时!)

#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>

using namespace std;

struct stu{
    int ac;
    double grade;
    char name[20];
};

stu stus[1000];
char str[100];

bool cmp(const stu& a,const stu& b){
    if(a.ac==b.ac)
        if(a.grade==b.grade)
            return strcmp(a.name,b.name)<0;
        else return a.grade<b.grade;
    else return a.ac>b.ac;
}

void rp(char *s,int n){
    int len=strlen(s);
    int i;

    for(i=0;i<n-len;i++)putchar(' ');
    printf(s);
}

int main(){
    int n,nstu;
    double m;
    double ta;
    int tb;
    int num,len;
    int tmp;
    int i,j;

    //freopen("d1t6.in","r",stdin);
    //freopen("d1t6.out","w",stdout);

    scanf("%d%lf",&n,&m);
    for(i=0;true;i++){
        if(scanf("%s",stus[i].name)==EOF)goto output;
        for(j=0;j<n;j++){
            num=scanf("%lf(%d)",&ta,&tb);
            //printf("%d %d %d\n",num,ta,tb);
            if(num==1){
                if(ta>0){
                    stus[i].ac++;
                    stus[i].grade+=ta;
                }
            }else{
                stus[i].ac++;
                stus[i].grade+=ta+tb*m;
            }
        }
    }

    output:
    nstu=i;
    sort(stus,stus+nstu,cmp);
    //printf("%d\n",nstu);
    for(i=0;i<nstu;i++){
        printf("%s",stus[i].name);
        len=strlen(stus[i].name);
        for(j=0;j<11-len;j++)putchar(' ');

        sprintf(str,"%d",stus[i].ac);
        rp(str,2);
        putchar(' ');
        if(floor(stus[i].grade)!=stus[i].grade)5/0;
        sprintf(str,"%d",tmp=stus[i].grade);
        rp(str,4);
        //putchar(' ');
        putchar('\n');
    }
    return 0;
}

G Olympiad

定义各位数字互不相同的数为美丽的数(美个头!),输入若干组 a,b ,问 [a,b] 内美丽的数的个数……

解法:
定义 an={0,1,n,n,
,则问题可转化为求 {an} 的前n项和 {Sn} ,继而使用记忆前缀和的方法求解。

#include <cstdio>

#define BMAX 100000

bool mp[10];
int s[BMAX+1];

bool isbeaut(int num){
    int i;

    for(i=0;i<10;i++)mp[i]=false;
    for(;num;num/=10)
        if(mp[num%10])return false;
        else mp[num%10]=true;
    return true;
}

int main(){
    int t;
    int ta,tb;
    int i,j;

    for(i=1;i<=BMAX;i++)
        s[i]=s[i-1]+isbeaut(i);

    scanf("%d",&t);
    for(i=0;i<t;i++){
        scanf("%d%d",&ta,&tb);
        printf("%d\n",s[tb]-s[ta-1]);
    }
    return 0;
}

H 鸡兔同笼

现有若干只鸡与若干只兔关在同一笼中,输入鸡和兔脚的总数n,求笼中鸡和兔总只数的最小值和最大值。

思想:类似于贪心
解法:若求最小值,则令笼中兔的数量尽可能多(有可能剩余两只脚,为鸡脚);反之若求总只数最大值,则令笼中全为鸡即可。
注意:看清题!差点以为是小学奥数解方程题……

#include <cstdio>

int main(){
    int a;
    int i;

    scanf("%d",&a);
    if(a%2)printf("0 0\n");
    else printf("%d %d\n",a/4+!!(a%4),a/2);
    return 0;
}

尾声

感受了一下acm的气氛,竞争还是很激烈的……切记就算所有题都会做也马虎不得……

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值