【2020 11th C++】蓝桥杯省赛

A. 门牌制作 \(\checkmark\)

题意

统计\(1\)\(2020\)的所有数中,总共有多少个字符\(2\)

题解

暴力遍历每个数的每一位,如果满足累计即可

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
int main()
{
    int ans=0;
    rep(i,1,2020+1)
    {
        int t=i;
        while(t)
        {
            if(t%10 == 2) ans++;
            t/=10;
        }
    }
    cout<<ans<<endl;
}

B. 既分约数

题意

如果一个分数的分子和分母的最大公约数是\(1\),这个分数称为既约分数。
例如,\(\frac{3}{4},\frac{5}{2},\frac{1}{8},\frac{7}{1}\)都是既约分数。求分子和分母都是\(1\)\(2020\)之间的整数(包括\(1\)\(2020\))有多少个既约分数?

题解

暴力判断任意两个数的\(gcd\)即可,如果为\(1\)就累计

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
int gcd(int a,int b){return b?gcd(b,a%b):a;}
int main() 
{
    int ans=0;
    rep(i,1,2020+1) rep(j,1,2020+1)
    {
        if(gcd(i,j)==1) ans++;
    }
    cout<<ans<<endl;
}

C. 蛇形填数

题意

按照如下所示的规则蛇形填数,求第\(20\)\(20\)列的数字是多少

1   2   6   7   15  ...
3   5   8   14  ...
4   9   13  ...
10  12  ...
11  ...
...

题解

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<n;i++)
#define per(i,a,n) for(int i=n-1;i>=a;i--)
int main() {
    int i = 1,j = 1,cnt = 2;
    int a[250][250];
    a[1][1] = 1;

    while (cnt <1000) {
        j++;

        while (i && j) {

            a[i][j] = cnt++;
            if (j == 1)
            break;
            i++;
            j--;
        }
        i++;
        while (i && j) {
            a[i][j] = cnt++;
            if (i == 1)
            break;
            i--;
            j++;
        }
    }   
    rep(i,1,21)
    {
        rep(j,1,21)
        {
            cout<<a[i][j]<<"\t";
        }
        cout<<endl;
    }
    cout << a[20][20];
    return 0;
}

D. 跑步锻炼

题意

正常情况下,小蓝每天跑\(1km\)。如果是周一或者月初(1日),跑\(2km\)
如果同时是周一或月初,也是跑\(2km\)
求出从\(2000\)\(1\)\(1\)日(周六)到\(2020\)\(10\)\(1\)日(周四)。请问这段时间小蓝总共跑步多少千米?

题解

闰年年数有\(366\)天,闰年的\(2\)月有\(29\)天,闰年的计算方法:

  • 能被\(400\)整除的年份

  • 能被\(4\)整除但不能被\(100\)整除的年份

  • 从星期六开始,星期六为\(1\),星期天为\(2\)进行计算

模拟天数即可

Code

#include <bits/stdc++.h>

using namespace std;

int days[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};

int main() 
{
    int year = 2000, month = 1, day = 1, num = 1, ans = 0;
    while(year != 2020 || month != 10 || day != 2) 
    {
        if(day == 1 || num % 7 == 3) ans += 2;
        else ans += 1;
        int nowday = days[month];
        if((year % 400 == 0 || (year % 4 == 0 && year % 100 != 0)) && month == 2) nowday++;
        day++, num++;
        if(day > nowday) 
        {
            day = 1;
            month += 1;
        }
        if(month == 13) 
        {
            year += 1;
            month = 1;
        }
    }

    printf("%d\n", ans);
    return 0;
}

E. 七段码

题意

如图所示的一段七段码, 一部分二极管(至少要有一个)发光来表达字符。
在设计字符的表达时,要求所有发光的二极管是连成一片的。求一共可能表示成多少个不同的字符

题解

  • \(dfs\)或二进制枚举每个二极管是否被点亮

  • 并查集维护联通块的个数,因为要求的所有发光的二极管必须在同一个连通块中通过并查集维护

  • 判断每个二极管是否被使用,如果被使用的话标记,每次枚举一种状态的时候都去通过并查集合并联通的块即可

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<=n;i++)
const int N=10,M=10000;

bool st[N][N],use[N];
int fa[N],ans=0;
void init()
{
    st[1][2]=st[1][6]=1;
    st[2][1]=st[2][3]=st[2][7]=1;
    st[3][2]=st[3][7]=st[3][4]=1;
    st[4][3]=st[4][5]=1;
    st[5][4]=st[5][7]=1;
    st[6][5]=st[6][7]=st[6][1]=1;
    st[7][2]=st[7][3]=st[7][5]=st[7][6]=1;
}
int find(int x)
{
    if(fa[x]==x) return x;
    return fa[x]=find(fa[x]);
}
void dfs(int u)
{
    if(u>7)
    {
        rep(i,1,7) fa[i]=i;
        rep(i,1,7) rep(j,1,7)
        {
            if(st[i][j] && use[i] && use[j])
            {
                int pa=find(i),pb=find(j);
                if(pa!=pb) fa[pa]=pb;
            }
        }
        int block=0;
        rep(i,1,7) if(fa[i]==i && use[i]) block++;
        if(block==1) ans++;
        return;
    }
    use[u]=1;
    dfs(u+1);
    use[u]=0;
    dfs(u+1);
}

int main()
{
    init();
    dfs(1);
    cout<<ans<<endl;
}

F. 成绩统计

题意

给定\(n\)个人的分数,\(\geq 60\)几个,\(\geq 85\)优秀,求及格率和优秀率

题解

百分化\(\times 100\)后四舍五入即可

Code

#include <bits/stdc++.h>
using namespace std;
int main()
{
    int n; scanf("%d",&n);
    double a=0,b=0;
    for(int i=1;i<=n;i++)
    {
        int x; cin >> x;
        if( x>=60 ) a++;
        if( x>=85 ) b++;
    }
    a*=100;b*=100;
    a/=n;b/=n;
    printf("%.0lf",a);puts("%");
    printf("%.0lf",b);puts("%");
}

F. 回文日期

题意

\(20200202\),恰好是一个回文数。我们称这样的日期是回文日期。下一个回文日期为\(20211202\)\(20200202\)不仅是回文日期,还是一个\(ABABBABA\)型的回文日期。100年后就能遇到下一个ABABBABA型的回文日期:\(21211212\)。给定一个\(8\)位数的日期,计算该日期之后下一个回文日期和下一个\(ABABBABA\)型的回文日期各是哪一天。

题解

根据年份从当前年开始枚举,通过年确定月日判断是否满足条件

  • 需要特判当前年的年份得到的月日是否比给定的月日大

  • 如果合法取第一次更新的值即下一个回文日期和\(ABAB\)型日期

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<=n;i++)

int ans,lans;
int days[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
bool checkyear(int x)
{
    if(x%400==0) return 1;
    if(x%100) return 0;
    if(x%4==0) return 1;
    return 0;
}
int main()
{
    int x;cin>>x;
    int lday = x%100;int lmonth=x%10000;
    lmonth=lmonth/100;
    x/=10000; // 表示年份

    for(int i=x;;i++)
    {
        if(checkyear(i)) days[2]=29;
        else days[2]=28;

        int t=i;
        int year[5];
        for(int j=1;j<=4;j++) 
            year[j]=t%10,t/=10;
        int nowmon=year[1]*10+year[2];
        int nowday=year[3]*10+year[4];

        if(i==x && lmonth>nowmon) continue; 
        if(i==x && lmonth==nowmon && lday>=nowday) continue;

        if(nowmon<=12 && nowmon>=1 && nowday>=1 && nowday<=days[nowmon])
        {
            if(ans==0) ans=i*10000+nowmon*100+nowday;
            if(year[1]==year[3] && year[2]==year[4]) lans=i*10000+nowmon*100+nowday;
        }
        if(ans&&lans)
        {
            cout<<ans<<endl<<lans<<endl;
            return 0;
        }
    }   

}

I. 平面切分

题意

平面上有\(n\)条直线,第\(i\)条表示为\(y=A_{i}x+B_{i}\)
求着\(n\)条直线将平面划分为了多少个点

题解

  • 在读入过程中将所有支线存入\(set\),利用\(set\)首先对所有的直线去重

  • 两重循环遍历之前的所有线段,两两求出交点,当前线段多划分出来的平面等于交点数\(+1\)

  • 交点的坐标通过等式变换可以得到

Code

#include<bits/stdc++.h>
using namespace std;
#define rep(i,a,n) for(int i=a;i<=n;i++)
#define fi first 
#define se second
#define mp make_pair
const int N=1010;
double a[N];
double b[N];
set<pair<double,double>>s;
set<pair<double,double> >::iterator it;
int n;
int main()
{
    cin>>n;
    rep(i,1,n) 
    {
        int x,y;
        cin>>x>>y;
        s.insert(make_pair(x,y));
    }
    n=s.size();
    int i=0;
    for(it=s.begin();it!=s.end();it++)
    {
        a[++i]=(*it).fi;
        b[i]=(*it).se;
    }
    long long ans=2; //最开始一条线将平面一分为二
    rep(i,2,n) 
    {
        set<pair<double,double>>h;
        rep(j,1,i)
        {
            double x=(b[j]-b[i])/(a[i]-a[j]);
            double y=(a[i]*b[j]-a[j]*b[i])/(a[i]-a[j]);
            h.insert(make_pair(x,y));   
        }
        ans+=h.size()+1;
    }
    cout<<ans<<endl;
}
/*
3
1 1
2 2
3 3
*/

J. 字符串排序

题意

小蓝最近学习了一些排序算法,其中冒泡排序让他印象深刻。
在冒泡排序中,每次只能交换相邻的两个元素。小蓝发现,如果对一个字符串中的字符排序,只允许交换相邻的两个字符,则在所有可能的排序方案中,冒泡排序的总交换次数是最少的。
例如,对于字符串 \(lan\) 排序,只需要 \(1\) 次交换。对于字符串 \(qiao\)排序,总共需要 \(4\) 次交换。
小蓝找到了很多字符串试图排序,他恰巧碰到一个字符串,需要 \(V\) 次交换,可是他忘了把这个字符串记下来,现在找不到了。
请帮助小蓝找一个只包含小写英文字母且没有字母重复出现的字符串,对该串的字符排序,正好需要 \(V\) 次交换。如果可能找到多个,请告诉小蓝最短的那个。如果最短的仍然有多个,请告诉小蓝字典序最小的那个。请注意字符串中可以包含相同的字符。

题解

样例1:

4

输出

bbaa

样例2:

100

输出

jihgfeeddccbbaa
  • 对于相同交换次数的优先找字符串长度较短的

  • 对于字符串长度相同的优先找字典序小的

Code

1 ba 1
2 baa 1+1
3 cba 2+1
4 bbaa 2+2
5 cbaa 2+2+1
6 dcba 3+2+1
7 cbaaa 2+2+2+1
8 cbbaa 3+3+1+1
9 dcbaa 3+3+2+1
10 edcba 4+3+2+1
11 cbbaaa 3+3+3+1+1
12 ccbbaa 4+4+2+2
13 dcbbaa 4+4+2+2+1
14 edcbaa 4+4+3+2+1
15 fedcba 5+4+3+2+1
16 ccbbaaa 4+4+4+2+2
17 dcbbaaa 4+4+4+2+2+1
18 dccbbaa 5+5+3+3+1+1
19 edcbbaa 5+5+3+3+2+1
20 fedcbaa 5+5+4+3+2+1
21 gfedcba 6+5+4+3+2+1
22 dcbbbaaa 5+5+5+2+2+2+1
23 dccbbaaa 5+5+5+3+3+1+1
24 ddccbbaa 6+6+4+4+2+2
25 edccbbaa 6+6+4+4+2+2+1
26 fedcbbaa 6+6+4+4+3+2+1
27 gfedcbaa 6+6+5+4+3+2+1
28 hgfedcba 7+6+5+4+3+2+1
posted @ 2020-10-26 21:23  Hyx'  阅读(11)  评论(0编辑  收藏  举报