美文网首页
2017年蓝桥杯C++组真题解析2

2017年蓝桥杯C++组真题解析2

作者: 你要好好学习呀 | 来源:发表于2019-03-23 18:57 被阅读0次
    题目7:日期问题

    小明正在整理一批历史文献。这些历史文献中出现了很多日期。小明知道这些日期都在1960年1月1日至2059年12月31日。
    令小明头疼的是,这些日期采用的格式非常不统一,有采用年/月/日的,有采用月/日/年的,还有采用日/月/年的。
    更加麻烦的是,年份也都省略了前两位,使得文献上的一个日期,存在很多可能的日期与其对应。
    比如02/03/04,可能是2002年03月04日、2004年02月03日或2004年03月02日。
    给出一个文献上的日期,你能帮助小明判断有哪些可能的日期对其对应吗?
    输入:
    一个日期,格式是"AA/BB/CC"。 (0 <= A, B, C <= 9)
    输出:
    输出若干个不相同的日期,每个日期一行,格式是"yyyy-MM-dd"。多个日期按从早到晚排列。
    样例输入
    02/03/04
    样例输出
    2002-03-04
    2004-02-03
    2004-03-02

    资源约定:
    峰值内存消耗(含虚拟机) < 256M
    CPU消耗 < 1000ms

    #include <bits/stdc++.h>
    using namespace std;
    bool isLeap(int year){
        return ((year%4==0 && year%100!=0)|| year&400==0);
    }
    void i2s(int n,string &str){//注意
        stringstream ss;
        ss<<n;
        ss>>str;
    }
    string f(int a,int b,int c){
        if(a>=0 && a<=59)a+=2000;
        else if(a>=60 && a<=99)a+=1900;
        else return "";
    
        if(b<1 || b>12) return "";
        if(c<1 || c>31) return "";
    
        bool _isLeap=isLeap(a);
        switch(b){//日期校验
            case 2:
                if(_isLeap && c>29) return "";
                if(!_isLeap && c>28) return "";
                break;
            case 4:
                if(c>30) return "";
                break;
            case 6:
                if(c>30) return "";
                break;
            case 9:
                if(c>30) return "";
                break;
            case 11:
                if(c>30) return "";
                break;
            default:
                break;
    
        }
        string _a,_b,_c;
        i2s(a,_a);
        i2s(b,_b);
        i2s(c,_c);
        if(_b.length()==1)_b="0"+_b;////C++中不能使用string型的="0"+int型的--重要
        if(_c.length()==1)_c="0"+_c;
        return _a+"-"+_b+"-"+_c;
    }
    
    int main()
    {
        string in;
        cin>>in;
        int a=0,b=0,c=0;
        a=(in[0]-'0')*10+(in[1]-'0');//单个字符转数字
        b=(in[3]-'0')*10+(in[4]-'0');
        c=(in[6]-'0')*10+(in[7]-'0');
        string case1=f(a,b,c);
        string case2=f(c,a,b);
        string case3=f(c,b,a);
        //注意排序和去重
        set<string> ans;//set中的元素都是排好序的,set中没有重复的元素
        if(case1!="") ans.insert(case1);
        if(case2!="") ans.insert(case2);
        if(case3!="") ans.insert(case3);
        //迭代器的使用来遍历set中的元素
        /*
        begin(),返回set容器第一个元素的迭代器
        end(),返回一个指向当前set末尾元素的下一位置的迭代器.
        */
        for(set<string>::iterator iter=ans.begin();iter!=ans.end();iter++){
            cout<<*iter<<endl;
        }//重要
        return 0;
    }
    
    题目8:包子凑数

    小明几乎每天早晨都会在一家包子铺吃早餐。
    他发现这家包子铺有N种蒸笼,其中第i种蒸笼恰好能放Ai个包子。每种蒸笼都有非常多笼,可以认为是无限笼。
    每当有顾客想买X个包子,卖包子的大叔就会迅速选出若干笼包子来,使得这若干笼中恰好一共有X个包子。比如一共有3种蒸笼,分别能放3、4和5个包子。当顾客想买11个包子时,大叔就会选2笼3个的再加1笼5个的(也可能选出1笼3个的再加2笼4个的)。

    当然有时包子大叔无论如何也凑不出顾客想买的数量。
    比如一共有3种蒸笼,分别能放4、5和6个包子。而顾客想买7个包子时,大叔就凑不出来了。

    小明想知道一共有多少种数目是包子大叔凑不出来的。
    输入

    第一行包含一个整数N。(1 <= N <= 100)
    以下N行每行包含一个整数Ai。(1 <= Ai <= 100)
    输出

    一个整数代表答案。如果凑不出的数目有无限多个,输出INF。

    例如:
    输入:
    2
    4
    5

    程序应该输出:
    6

    再例如,
    输入:
    2
    4
    6

    程序应该输出:
    INF

    样例解释:
    对于样例1,凑不出的数目包括:1, 2, 3, 6, 7, 11。
    对于样例2,所有奇数都凑不出来,所以有无限多个。

    资源约定:
    峰值内存消耗(含虚拟机) < 256M
    CPU消耗 < 1000ms

    #include <bits/stdc++.h>
    using namespace std;
    
    int n;//n种蒸笼
    int g;//最大公约数
    bool f[10000];
    int a[101];
    //最大公约数,是指公有的因数中最大的那个
    //辗转相除法:辗转相除法是求两个自然数的最大公约数的一种方法,也叫 欧几里德算法
    //最小公倍数=X/gcd(x,y)*Y
    int gcd(int a,int b){//重要
        if(b==0) return a;//递归出口
        return gcd(b,a%b);
    }
    int main(){
        scanf("%d",&n);
        f[0]=true;
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
            if(i==1) g=a[i];//初始化最大公约数
            else g=gcd(a[i],g);
            for(int j=0;j<10000;j++){
                if(f[j])f[j+a[i]]=true;
            }
        }
        if(g!=1){
            printf("INF\n");
            return 0;//不要忘记
        }
        //统计个数
        int ans=0;
        for(int k=0;k<10000;k++)
        {
            if(!f[k]){
                ans++;
                //cout<<k<<endl;
            }
        }
        printf("%d",ans);
    }
    
    题目9:分巧克力

    儿童节那天有K位小朋友到小明家做客。小明拿出了珍藏的巧克力招待小朋友们。
    小明一共有N块巧克力,其中第i块是Hi x Wi的方格组成的长方形。
    为了公平起见,小明需要从这 N 块巧克力中切出K块巧克力分给小朋友们。切出的巧克力需要满足:
    1. 形状是正方形,边长是整数
    2. 大小相同
    例如一块6x5的巧克力可以切出6块2x2的巧克力或者2块3x3的巧克力。
    当然小朋友们都希望得到的巧克力尽可能大,你能帮小Hi计算出最大的边长是多少么?

    输入
    第一行包含两个整数N和K。(1 <= N, K <= 100000)
    以下N行每行包含两个整数Hi和Wi。(1 <= Hi, Wi <= 100000)
    输入保证每位小朋友至少能获得一块1x1的巧克力。

    输出
    输出切出的正方形巧克力最大可能的边长。

    样例输入:
    2 10
    6 5
    5 6

    样例输出:
    2

    资源约定:
    峰值内存消耗(含虚拟机) < 256M
    CPU消耗 < 1000ms

    //先暴力枚举,再考虑如何优化
    
    #include <bits/stdc++.h>
    using namespace std;
    int n,k;
    int h[100000];
    int w[100000];
    /*贪心暴力枚举
    int main()
    {
        scanf("%d%d",&n,&k);
        for(int i=0;i<n;i++)
        {
            cin>>h[i]>>w[i];
        }
        for(int len=100000;len>0;len--)//枚举切成的巧克力块的边长
        {
            int cnt=0;
            for(int j=0;j<n;j++){//枚举大巧克力块数
                cnt+=(h[j]/len)*(w[j]/len);
            }
            if(cnt>=k){
                cout<<len<<endl;
                return 0;
            }
        }
        return 0;
    }
    */
    //使用二分法试探-满足则试探更大的,更新结果;否则试探更小的
    int main()
    {
        scanf("%d%d",&n,&k);
        for(int i=0;i<n;i++)
        {
            cin>>h[i]>>w[i];
        }
        int r=100001;
        int l=1;
        int ans=0;
        while(l<=r)
        {
            int mid=(l+r)/2;//试探边长
            int cnt=0;
            for(int j=0;j<n;j++){//枚举大巧克力块数
                cnt+=(h[j]/mid)*(w[j]/mid);
            }
            if(cnt>=k){
                l=mid+1;
                ans=mid;
            }else{
                r=mid-1;
            }
        }
        cout<<ans<<endl;
        return 0;
    }
    
    题目10:K倍区间

    给定一个长度为N的数列,A1, A2, ... AN,如果其中一段连续的子序列Ai, Ai+1, ... Aj(i <= j)之和是K的倍数,
    我们就称这个区间[i, j]是K倍区间。
    你能求出数列中总共有多少个K倍区间吗?

    输入
    第一行包含两个整数N和K。(1 <= N, K <= 100000)
    以下N行每行包含一个整数Ai。(1 <= Ai <= 100000)

    输出
    输出一个整数,代表K倍区间的数目。

    例如,
    输入:
    5 2
    1
    2
    3
    4
    5

    程序应该输出:
    6

    //暴力枚举复杂度太高,可以使用前缀和来优化-但还不是太高效
    /*
    #include <bits/stdc++.h>
    using namespace std;
    int n,k;
    int a[100010];
    int s[100010];
    
    int main()
    {
        cin>>n>>k;
        s[0]=0;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            s[i]=s[i-1]+a[i];
        }
        long long ans=0;
        //枚举i和j
        for(int i=1;i<=n;i++){
            for(int j=i;i<=n;j++)
            {
                if((s[j]-s[i-1])%k==0)
                    ans++;
            }
        }
        return 0;
    }*/
    //用同余的知来解
    // 若amodm==bmodm,则 a 和 b 之差是 m 的倍数)
    #include <bits/stdc++.h>
    using namespace std;
    int n,k;
    int a[100010];
    int s[100010];
    map<int,int> cnt;//同余个数统计
    
    int main()
    {
        cin>>n>>k;
        s[0]=0;
        cnt[0]=1;
        for(int i=1;i<=n;i++)
        {
            cin>>a[i];
            s[i]=(s[i-1]+a[i])%k;
            cnt[s[i]]++;
        }
        long long ans=0;
        for(int i=0;i<k;i++){//余数必然在0-k-1之间
            ans+=(long long)cnt[i]*(cnt[i]-1)/2;//例如所有前缀和中%k==3的有3个,则它们中任选2个可组合出一种结果(3*2)/2
        }
        cout<<ans<<endl;
        return 0;
    }
    /*
     Map是c++的一个标准容器,她提供了很好一对一的关系,在一些程序中建立一个map可以起到事半功倍的效果,总结了一些map基本简单实用的操作!
    1. map最基本的构造函数;
       map<string , int >mapstring;         map<int ,string >mapint;
       map<sring, char>mapstring;         map< char ,string>mapchar;
       map<char ,int>mapchar;            map<int ,char >mapint;
    2. map添加数据;
       map<int ,string> maplive;
       1.maplive.insert(pair<int,string>(102,"aclive"));
       2.maplive.insert(map<int,string>::value_type(321,"hai"));
       3, maplive[112]="April";//map中最简单最常用的插入添加!
    3,map中元素的查找:
       find()函数返回一个迭代器指向键值为key的元素,如果没找到就返回指向map尾部的迭代器。
       map<int ,string >::iterator l_it;
       l_it=maplive.find(112);
       if(l_it==maplive.end())
                    cout<<"we do not find 112"<<endl;
       else cout<<"wo find 112"<<endl;
    4,map中元素的删除:
       如果删除112;
       map<int ,string >::iterator l_it;;
       l_it=maplive.find(112);
       if(l_it==maplive.end())
            cout<<"we do not find 112"<<endl;
       else  maplive.erase(l_it);  //delete 112;
    */
    

    相关文章

      网友评论

          本文标题:2017年蓝桥杯C++组真题解析2

          本文链接:https://www.haomeiwen.com/subject/nmasvqtx.html