蓝桥杯大赛 ——首场算法团队战题解
1 不同角度
问题描述
在生活中,我们总是根据数值的大小来判断两个数字的大小关系。例如,9999 总是小于 100100,999999 总是小于 10001000。但如果我们换一个角度,将 999999 和 10001000 看成是两个数字字符串,并用字典序来比较它们的大小,那么此时,999999 将大于 10001000。
字典序的比较规则类似于字典中单词的排序:从左到右逐位比较,如果对应位置的字符不同,则较小的字符对应的字符串字典序较小;如果所有对应位置的字符都相同,则比较字符串的长度,较短的字符串字典序较小;如果长度也相同,则两个字符串字典序相同。
现在,给定一个自然数 SS,请你找到一个自然数 TT,使得将 SS、TT 转换为数字字符串后,(数字字符串)TT 的字典序大于(数字字符串)SS,并且在所有满足此条件的数字字符串中,(数字字符串)TT 的字典序是最小的。
输入格式
第一行包含一个整数 tt (1≤t≤103)(1≤t≤103),表示测试用例的数量。
接下来的 tt 行,每行包含一个不超过 109109 的自然数,表示 SS。
输出格式
对于每个测试用例,输出一个整数,表示满足条件的自然数 TT。
样例输入
2
99
999
样例输出
990
9990
贪心题。普通的数字在后面加0是大于并且字典序最小的,但是如果输入的是0,1才是最小的。
#include <iostream> using namespace std; int main() { string s; int t; for(cin>>t;t;t--) { cin>>s; if(s=="0") cout<<"1\n"; else cout<<s<<0<<endl; } }
6 看不清的数字
问题描述
今天是 1024 程序员节,大家都开开心心地去参加节日活动了,只有小蓝还在苦苦加班 😭。
起因是领导在小蓝的工位上贴了三张便利贴,上面写着三个范围在 11 到 NN 之间的正整数。可这三个数被一些同事涂鸦得乱七八糟,导致无法看清这三个数的确切数值,只知道:
-
三个数互不相同。
-
每个数的各个数位上都不包含数字 11、22 和 44。
-
三个数的和除以 10241024 的余数等于 MM。
于是,领导便要求小蓝加班找到所有满足上述条件的三个数,只有这样,小蓝才可以下班。
为了能尽快下班,享受这难得的节日,小蓝找到了你。现在,就请你帮助小蓝算算,总共有多少种满足条件的组合(如果通过改变三个正整数的顺序可以得到相同的组合,则这样的组合也被视为同一种。例如,对于 N=10,M=15N=10,M=15,无论是 (3,5,7)(3,5,7) 还是 (5,3,7)(5,3,7),都只算作一种)。
由于可能的组合数量可能非常巨大,你只需要输出答案对 109+7109+7 取余后的结果即可。
输入格式
第一行包含两个整数 NN 和 MM(3≤N≤10163≤N≤1016,0≤M≤10230≤M≤1023),其含义如题所述。
输出格式
输出仅一行,包含一个整数,表示满足条件的组合数量对 109+7109+7 取余后的结果。
样例输入
10 15
1
样例说明
满足条件的组合仅有一组:(3,5,7)(3,5,7)。
首先考虑计算cnt[x]表示1~n里%1024=x的数字数量,然后用cnt进行计数。
为了计算cnt[x],我们进行数位dp:f[i][j][k]表示在从高往低i位(i),是否卡着上界(j),%1024值为k的数字数量。转移时枚举第i位,这一位使用了数字j,前一位的%1024的值即可进行转移。
有了cnt之后,方案要么是i j k三个%1024各不相同的数;要么是i i k这种两个相同,一个不同的数,要么是i i i这种三个相同的数字。O(n^2)地枚举i j即可计算。
#include <bits/stdc++.h> using namespace std; typedef long long ll; char s[100]; ll len,f[100][2][2000],mod=1e9+7,cnt[2000],ans,m; ll ksm(ll a,ll b) { ll res=1; while(b){if(b&1)res=res*a%mod;a=a*a%mod;b>>=1;} return res; } int main() { scanf("%s",s); cin>>m; m=m%1024; len=strlen(s); for(int i=1;i<=9&&i<s[0]-'0';i++) { if(i==1||i==2||i==4) continue; f[0][0][i]=1; } if(s[0]!='1'&&s[0]!='2'&&s[0]!='4') f[0][1][s[0]-'0']=1; for(int i=1;i<len;i++) { for(int j=0;j<=9;j++) { if(j==1||j==2||j==4) continue; if(j!=0) f[i][0][j]=(f[i][0][j]+1)%mod; for(int l=0;l<1024;l++) { f[i][0][(l*10+j)%1024]=(f[i][0][(l*10+j)%1024]+f[i-1][0][l])%mod; if(j<s[i]-'0') f[i][0][(l*10+j)%1024]=(f[i][0][(l*10+j)%1024]+f[i-1][1][l])%mod; } } if(s[i]!='1'&&s[i]!='2'&&s[i]!='4') for(int l=0;l<1024;l++) f[i][1][(l*10+s[i]-'0')%1024]=(f[i][1][(l*10+s[i]-'0')%1024]+f[i-1][1][l])%mod; } for(int i=0;i<1024;i++) cnt[i]=(f[len-1][1][i]+f[len-1][0][i])%mod; for(int i=0;i<1024;i++) { for(int j=0;j<1024;j++) { int k=((m-i-j)%1024+1024)%1024; if(i!=j&&j!=k&&i!=k) ans=(ans+cnt[i]*cnt[j]%mod*cnt[k]%mod*ksm(6,mod-2)%mod )%mod; } int k=((m-i-i)%1024+1024)%1024; if(i!=k) ans=(ans+cnt[i]%mod*(cnt[i]-1)%mod*cnt[k]%mod*ksm(2,mod-2)%mod )%mod; else ans=(ans+cnt[i]*(cnt[i]-1)%mod*(cnt[i]-2)%mod*ksm(6,mod-2)%mod )%mod; } cout<<(ans+mod)%mod; }
7 三个公式
问题描述
给定一个长度为 NN 的 0101 数列 A1,A2,⋯,ANA1,A2,⋯,AN 和一个长度为 NN 的 0101 数列 B1,B2,⋯,BNB1,B2,⋯,BN。
对于一个整数对 x,yx,y(x≤yx≤y),定义公式 F(x,y)F(x,y)、G(x,y)G(x,y)、H(x,y)H(x,y) 分别为:F(x,y)=Ax+Ax+1+⋯+AyG(x,y)=Ax∨Ax+1∨⋯∨AyH(x,y)=Bx⊕Bx+1⊕⋯ByF(x,y)=Ax+Ax+1+⋯+AyG(x,y)=Ax∨Ax+1∨⋯∨AyH(x,y)=Bx⊕