2021年第12届蓝桥杯国赛做题记录

A:带宽:计算200Mbps=?MB/s。常识题,答案200/8=25
B

先打一个素数表,然后遍历即可。答案1903

bool check(int n):
while (m > 0) {
	int i = m % 10;
	if (i != 2 && i != 3 && i != 5 && i != 7)
		return 0;
	m /= 10;
}
return 1;
int main():
int n=20210605,res=0;
int k=init(n);
for (int i = 0; i < k; i++) {
	if (check(p[i])) {
		//printf("%d\n",i);
		res++;
	}
}

C
暴力即可。可以写一个简单的日期类。答案977

bool check(Date d) {
    string s=d.toString();
    int x=0;
    for(char c:s)    x+=c-'0';
    int y=(int)sqrt(x);
    //if(y*y==x) printf("%d\n",x);
    return y*y==x;
}
main:
while(!(now==end)) {
    if(check(now)) {
        res++;
        //puts(now.toString().c_str());
    }
    now=now.next();
}

D
不会


E:小写转大写:送分题,s[i]=s[i]-'a'+'A'

F

思路1:约定f(x)=(x*(x+1))/2。不难得出前p段的数字个数等于第p段所有数字的和
首先由等差数列求和公式算出liri分别位于哪一段。(可用二分法)如果位于相同的段则要特别处理,(这点以后一定要注意)。
否则,假设二者分别位于pl与pr段,则(pl,pr)之间的段都可以用f(i)直接算出来,
再算出第l个数在pl段中是第几个(也就是算出第l个数的值,假设为left),办法是算出前pl-1段有多少个(即f(pl-1)),用l-left即得;最后计算f(pl)-f(left)即可
同理算出第r个数在pr段中是第几个。这种方法对应70%数据。

inline int part(llong i) {
    int p=1;
    int l=1,r=1e7;
    while(l<r) {  //二分查找,相当于lower_bound
    	p=(l+r)/2;  //假设第p段
		llong st=calc(1,p-1)+1; //计算第p段第一项
		if(st>i) {  //如果i于st,则说明答案在右半段
			r=p;
		}
		else {
			l=p+1;
		}
	}
    return l-1;
}
int main() {
//省略输入
    while(t--) {
        llong l,r,res=0;
        scanf("%lld%lld",&l,&r);
        int par_l=part(l),par_r=part(r);  //计算二者是在哪段
        //printf("%d %d\n",par_l,par_r);
        for(int i=par_l+1; i<par_r; i++) {
            res+=calc(1,i);
        }
        llong left=l-calc(1,par_l-1),right=r-calc(1,par_r-1);  //单独处理“左边距”与“右边距”
        if(par_l!=par_r) {
            res+=calc(left,par_l)+calc(1,right);
        }
        else {
        	res+=calc(left,right);
		}
        printf("%lld\n",res);
    }
}

思路2:针对main()中for循环,可在思路1的基础上推公式。可过全部数据。
个人觉得这种题适合出在蓝桥杯中,毕竟很多解法都能拿部分分。

G1
G2

方法1:暴力,能过40%
方法2:找循环节,把循环节存下来。但不排除爆空间风险。能过>=80%

char tt[M]; //使用char[]提高性能
int main() {
    NO_SYNC;
    int n;llong t;
    cin>>n>>t;
    string s,org;
    cin>>s;
    org=s;
    strs.reserve(n);
    strs.push_back(org);
    do {
        tt[0]=s[0];
        for(int i=1; i<n; i++) {
            tt[i]= (char)((s[i]-'0')^(s[i-1]-'0'))+'0';
        }
        s=tt;
        strs.push_back(s);
    } while(s!=org);
    strs.pop_back();
    cout<<strs[t%strs.size()];
}

H1
H2

若最高位为0,则只要在低位中取k个1即可。这部分可利用组合数公式。
最高位为1,符合条件的最小数为100....11b(共t位,有k个1,除最高位外的k-1个1均在最低位连续排列)最大为min(n,111....00b)(共t位前K个为1)。只要遍历这部分数即可。如果利用__builtin_popcount复杂度大约O(n2)。虽然还是过不了,不过数据出的好的话能混60%。
当然,考场上为节约时间这部分就不要考虑什么最小数最大数了。虽然可能少几分但有时间做别的题目。
正解数位DP,详参:https://blog.csdn.net/As_zyh/article/details/117637080


I
不会,但应该属于RMQ问题,可以设左括号为0,右括号为1,用线段树或分块说不定可行。


j1
J2

首先a ^ b ^ c == 0-->a ^ b == c,由异或的定义知这个式子的三个数可以任意互换位置。因此只要算出a<b<c时的结果*6即可。
这里还有一个优化:设f[i]=log2i+1,则对任意的i,若j<f[i]则不可能有i ^ j > j,因此从f[i]开始遍历即可。
同上,考试时节约时间就不要往这上想了。反正不太可能会多一分

自己做能有5+5+10+15+10+16+6+5=72分,在考场上就不知道能怎样了。

posted @   m0_51303687  阅读(219)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示