CCNU ACM 2016夏季集训·day4模拟赛(!!!)

做毛子题,你会感觉你辜负了你的基因;做美帝题,你会感觉你辜负了你的算法老师;做天朝题,你会觉得你辜负了你的小学语文老师、小学数学老师、小学英语老师,以及高中那个教你c艹的前辈……(被各种输入格式、输出格式等细节坑死了……)

题解时间到……


A 国王的切糕

输入两个整数 n,m ,表示一个 n×m 的矩形,每次从矩形中切最大的正方形,问切几次能够把矩形完全切成若干个正方形。

做法:gcd

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>

using namespace std;

int gcd(int a,int b,int n){return b?gcd(b,a%b,n+a/b):n;}

int main(){
    int t,tn,tm;
    int i,j;

    scanf("%d",&t);
    for(i=0;i<t;i++){
        scanf("%d%d",&tn,&tm);
        if(tn<tm)swap(tn,tm);
        printf("%d\n",gcd(tn,tm,0));
    }
    return 0;
}

B 国王的手机

(题目不再复述)

坑点:注意题上 si 的范围,可能出现 si=9 si>9
注意:如果被跳过的中间点之前已经经过,不认定密码无效,以及判断密码无效以后要继续读完整组数据。

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>

using namespace std;

int nok[][3]={
    1,2,3,
    4,5,6,
    7,8,9,

    1,4,7,
    2,5,8,
    3,6,9,

    1,5,9,
    3,5,7,
};

bool mp[10];

bool is_okay(int l,int t){
    int i;

    if(t>9||t==0||mp[t])return false;
    mp[t]=true;
    if(l==-1)return true;
    if(l>t)swap(l,t);
    for(i=0;i<8;i++)
        if((l==nok[i][0])&&(t==nok[i][2])&&(!mp[nok[i][1]]))return false;
    return true;
}

int main(){
    int t,n;
    int tmp,last;
    bool b;
    int i;

    scanf("%d",&t);
    while(t--){
        scanf("%d",&n);
        tmp=-1;
        b=(n>=4);
        for(i=0;i<10;i++)mp[i]=false;
        for(i=0;i<n;i++){
            last=tmp;
            scanf("%d",&tmp);
            if(b)b=b&&is_okay(last,tmp);
        }
        printf(b?"valid\n":"invalid\n");
    }
    return 0;
}

C 雷达安装

坑点:可能有根本覆盖不到的点(直接sqrt会re),以及奇葩的输出格式(我当时瞪着这个楞没看出来……)
无坑版:遥感监测(顺便推销cogs)
注意:即使检测到输入不合法,也要继续读完整组数据……

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
#include <cmath>

using namespace std;

#define NMAX 1000

struct seg{
    double l,r;

    bool operator < (const seg& b)const{return (r==b.r)?(l>b.l):(r<b.r);}
};

seg ss[NMAX];

int main(){
    int n,d;
    double dx;
    double last;
    int num;
    int tx,ty;
    bool b;
    int i,ybz;

    for(ybz=1;true;ybz++){
        b=true;
        scanf("%d%d",&n,&d);
        if((!n)&&(!d))return 0;
        for(i=0;i<n;i++){
            scanf("%d%d",&tx,&ty);
            if(abs(ty)>d)b=false;
            else{
                dx=sqrt(d*(double)d-ty*(double)ty);
                ss[i].l=tx-dx;
                ss[i].r=tx+dx;
            }
        }

        if(!b){
            printf("Case %d: -1\n",ybz);
            continue;
        }
        sort(ss,ss+n);

        num=1;
        last=ss[0].r;
        for(i=1;i<n;i++)
            if(ss[i].l>last){
                num++;
                last=ss[i].r;
            }
        printf("Case %d: %d\n",ybz,num);
    }
    return 0;
}

D ztr喜爱幸运数

输入一个数 x ,输出大于x的最小的仅由相等数量的数字 4 和数字7组成的数。

思路:dfs+剪枝(也可以提前打表然后二分查找)
(感觉自己代码能力下降了好多,原来写得最拿手的递归暴搜都写不出来了……)

比赛版
#include <cstdio>
#include <cctype>
#include <cstring>

using namespace std;

#define LMAX 50

int l;
char str[LMAX],num[LMAX],ans[LMAX];

bool dfs(char ind,bool isg,char num4,char num7){
    if(ind==-1){
        bool b=false;
        int i;

        for(i=LMAX-1;i>=0;i--)
            if(b||ans[i]||!i){
                putchar('0'+ans[i]);
                b=true;
            }
        putchar('\n');
        return true;
    }

    if(num4>0&&(isg||4>=num[ind])){
        ans[ind]=4;
        if(dfs(ind-1,(isg||4>num[ind]),num4-1,num7))return true;
    }

    if(num7>0&&(isg||7>=num[ind])){
        ans[ind]=7;
        if(dfs(ind-1,(isg||7>num[ind]),num4,num7-1))return true;
    }
    return false;
}

int main(){
    int t,l;
    int i;

    scanf("%d",&t);
    while(t--){
        scanf("%s",str);
        l=strlen(str);
        for(i=0;i<LMAX;i++)num[i]=ans[i]=0;
        for(i=0;i<l;i++)num[l-i-1]=str[i]-'0';
        l+=l%2;
        if(!dfs(l-1,false,l/2,l/2))
            dfs(l+1,false,l/2+1,l/2+1);
    }
    return 0;
}
优美版
#include <cstdio>
#include <cctype>
#include <cstring>

using namespace std;

#define LMAX 50
#define NUMAVL 2

int l;
char avl[NUMAVL]={4,7};
char numavl[NUMAVL];
char str[LMAX],num[LMAX],ans[LMAX];

bool dfs(char ind,bool isg){
    int i;

    if(ind==-1){
        for(i=l-1;i>=0;i--)putchar('0'+ans[i]);
        putchar('\n');
        return true;
    }else for(i=0;i<NUMAVL;i++)
        if(numavl[i]>0&&(isg||avl[i]>=num[ind])){
            ans[ind]=avl[i];
            numavl[i]--;
            if(dfs(ind-1,(isg||avl[i]>num[ind])))return true;
            numavl[i]++;
        }
    return false;
}

int main(){
    int t;
    int i;

    scanf("%d",&t);
    while(t--){
        scanf("%s",str);
        l=strlen(str);
        for(i=0;i<l;i++)num[l-i-1]=str[i]-'0';
        for(;i<LMAX;i++)num[i]=0;
        l+=(NUMAVL-l%NUMAVL)%NUMAVL-NUMAVL;
        do{
            l+=NUMAVL;
            for(i=0;i<NUMAVL;i++)numavl[i]=l/NUMAVL;
        }while(!dfs(l-1,false));
    }
    return 0;
}

E DZY喜爱个球

输入一个长度为 n 的数列,从中不放回地随机取出A B 两个数,问P(A>B)

知识:概率的定义
做法:前缀和

#include <cstdio>

using namespace std;

#define AMAX 300
#define NMAX 300

int mp[AMAX+1],sum[AMAX+1];
int num[NMAX];

int main(){
    int t,n;
    int tmp;
    int i;

    scanf("%d",&t);
    while(t--){
        for(i=0;i<=AMAX;i++)mp[i]=sum[i]=0;
        scanf("%d",&n);
        for(i=0;i<n;i++){
            scanf("%d",num+i);
            mp[num[i]]++;
        }
        for(i=1;i<=AMAX;i++)sum[i]=sum[i-1]+mp[i];

        tmp=0;
        for(i=0;i<n;i++)
            tmp+=sum[num[i]-1];
        printf("%lf\n",tmp/(n*(double)(n-1)));
    }
    return 0;
}

F CA爷喜爱棒棒

输入四个数 a,b,c,d ,问长为 a,b,c,d 的四条线段能否围成一个四边形。

坑点:long long类型所能表示的范围……

#include <cstdio>
#include <cctype>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>

using namespace std;

typedef unsigned long long u64;

u64 l[4];

int main(){
    int t;
    bool b;
    int i,j;

    scanf("%d",&t);
    for(i=0;i<t;i++){
        b=true;
        for(j=0;j<4;j++){
            scanf("%I64u",l+j);
            if(l[j]==0)b=false;
        }
        sort(l,l+4);
        if(l[0]+l[1]>l[3]-l[2]&&b)printf("Yes\n");
        else printf("No\n");
    }
    return 0;
}

尾声

结果是相当的惨……

看清题!!!!!!!!!!
看清题!!!!!!!!!!
看清题!!!!!!!!!!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值