- 题目全收集;
- 答案目前是群里面过的,有误可以评论区指正下;
- 大题标记了可能拿分,还不能确定100%对
小蓝家的网络带宽是 200 Mbps,请问,使用小蓝家的网络理论上每秒钟最多可以从网上下载多少 MB 的内容。
200M带宽 实际网速每秒25M 带宽 除以 8 等于 每秒网速
如果一个正整数只有 1 和它本身两个约数,则称为一个质数(又称素数)。
前几个质数是:2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, · · · 。
如果一个质数的所有十进制数位都是质数,我们称它为纯质数。例如:2, 3, 5, 7, 23, 37 都是纯质数,而 11, 13, 17, 19, 29, 31 不是纯质数。当然 1, 4, 35也不是纯质数。
请问,在 1 到 20210605 中,有多少个纯质数?
思路:暴力模拟
#include
#include
#define ll long long
using namespace std;
// 0 1 2 3 4 5 6 7 8 9
int book[11] = {
0,0,1,1,0,1,0,1,0,0};
int noprime[100000000];
void check(){
int e = 20210605;
noprime[0] = 1,noprime[1] = 1,noprime[2] = 0;
for(int i = 2; i <= e; i++){
if(!noprime[i]){
for(int j = i * 2; j <= e; j+=i){
noprime[j] = 1;
}
}
}
}
int check(int i){
if(noprime[i]) return 0;
while(i){
int n = i % 10;
if(!book[n]) return 0;
i /= 10;
}
return 1;
}
int main(){
int ans = 0;
check();
for(int i = 1; i <=20210605; i++){
ans += check(i);
}
cout << ans;
return 0;
}
如果一个日期中年月日的各位数字之和是完全平方数,则称为一个完全日期。
例如:2021 年 6 月 5 日的各位数字之和为 2 + 0 + 2 + 1 + 6 + 5 = 16,而
16 是一个完全平方数,它是 4 的平方。所以 2021 年 6 月 5 日是一个完全日期。
例如:2021 年 6 月 23 日的各位数字之和为 2 + 0 + 2 + 1 + 6 + 2 + 3 = 16,
是一个完全平方数。所以 2021 年 6 月 23 日也是一个完全日期。
请问,从 2001 年 1 月 1 日到 2021 年 12 月 31 日中,一共有多少个完全日期?
解题思路,,暴力模拟/EXCEl公式拉取
因为忘记excel怎么算日期位和了,感觉手写更快
如果那边会操作一行代码拉一下就出来了
//T3
#include
#include
#define ll long long
using namespace std;
// 1 2 3 4 5 6 7 8 9 10
int month[13] = {
0,31,28,31,30,31,30,31,31,30,31,30,31};
int month1[13] = {
0,31,29,31,30,31,30,31,31,30,31,30,31};
int run(int y){
if(( y % 4 == 0 && y % 100!=0) || y % 400 == 0){
return 1;
}
return 0;
}
int check(int y,int m,int d){
int sum = 0;
while(y){
sum += (y % 10);
y /= 10;
}
while(m){
sum += (m % 10);
m /= 10;
}
while(d){
sum += (d % 10);
d /= 10;
}
for(int i = 1; i <= 20; i++){
if(i*i == sum){
return 1;
}
}
return 0;
}
int main(){
int y = 2001,m = 1,d = 1;
int ans = 0;
while(1){
int flag = check(y,m,d);
if(flag){
cout << y << m << d << endl;
}
ans += flag;
if(y == 2021 && m == 12 && d == 31)
break;
d++;
if(run(y)){
if(d > month1[m]){
m++;
d = 1;
}
}else{
if(d > month[m]){
m++;
d = 1;
}
}
if(m > 12){
y++;
m = 1;
}
}
cout << ans;
return 0;
}
对于一棵有根二叉树 _T _,小蓝定义这棵树中结点的权值 W(_T _) 如下:空子树的权值为 0。
如果一个结点 v 有左子树 L, 右子树 R,分别有 C(L) 和 C® 个结点,则
W(v) = 1 + 2W(L) + 3W® + (C(L))2 C®。
树的权值定义为树的根结点的权值。
小蓝想知道,对于一棵有 2021 个结点的二叉树,树的权值最小可能是多少?
解题思路:考试的时候觉得全是左子树的话 2021次方太大就就没想了,后面没时间了,但早知道就python写上了
# py语法有点忘了,忽略,大致就下面这样
ans = 0;
for num in range(1,2021):
ans = 2*ans + 1
print(ans)
另一种说法:
W[V] = 1 + 2W(L) + 3W® + (C(L))2 C®
dp(n)=1+2dp(i)+3dp(n-i-1)+ii(n-i-1)
用dp去推算
时间限制: 1.0s 内存限制: 256.0MB
给定一个只包含大写字母和小写字母的字符串,请将其中所有的小写字母转换成大写字母后将字符串输出。
【输入格式】
输入一行包含一个字符串。
【输出格式】
输出转换成大写后的字符串。
【样例输入 1】
LanQiao
【样例输出 1】
LANQIAO
【评测用例规模与约定】
对于所有评测用例,字符串的长度不超过 100。
这题我甚至以为我在打省赛签到题
我好像忘记cout输出了。。尴尬
#include
#include
#define ll long long
using namespace std;
int main(){
string str;
cin >> str;
for(int i = 0; i < str.length(); i++){
if(str[i] >= 'a' && str[i] <= 'z'){
str[i] -= ('a'-'A');
}
}
cout << str;
return 0;
}
时间限制: 1.0s 内存限制: 256.0MB
小蓝发现了一个有趣的数列,这个数列的前几项如下:
1, 1, 2, 1, 2, 3, 1, 2, 3, 4, …
小蓝发现,这个数列前 1 项是整数 1,接下来 2 项是整数 1 至 2,接下来
3 项是整数 1 至 3,接下来 4 项是整数 1 至 4,依次类推。小蓝想知道,这个数列中,连续一段的和是多少。
【输入格式】
输入的第一行包含一个整数 _T _,表示询问的个数。
接下来 _T _行,每行包含一组询问,其中第 _i _行包含两个整数 _li _和 ri,表示询问数列中第 _li _个数到第 _ri _个数的和。
【输出格式】
输出 _T _行,每行包含一个整数表示对应询问的答案。
【样例输入】
3
1 1
1 3
5 8
【样例输出】
1
4
8
【评测用例规模与约定】
对于 10% 的评测用例,1 ≤ _T _≤ 30, 1 ≤ _li _≤ _ri _≤ 100。 对于 20% 的评测用例,1 ≤ _T _≤ 100, 1 ≤ _li _≤ _ri _≤ 1000。对于 40% 的评测用例,1 ≤ _T _≤ 1000, 1 ≤ _li _≤ _ri _≤ 106。对于 70% 的评测用例,1 ≤ _T _≤ 10000, 1 ≤ _li _≤ _ri _≤ 109。对于 80% 的评测用例,1 ≤ _T _≤ 1000, 1 ≤ _li _≤ _ri _≤ 1012。
对于 90% 的评测用例,1 ≤ _T _≤ 10000, 1 ≤ _li _≤ _ri _≤ 1012。对于所有评测用例,1 ≤ _T _≤ 100000, 1 ≤ _li _≤ _ri _≤ 1012。
将数列看成金字塔,转换成求第na层第ca个数到nb层cb个数中间
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
思路举例:
例题的5 8 ==> 8
[第3层第2个数] --[第4层第2个数] :(2 + 3)[第三层后面]+ 0[中间层] + (1 + 2)[第四层前面] = 8
再举个好看的例子: 4 15 ==> 21
[第3层第1个数] – [第5层第5个数] : (6)第三层后面 + 10 中间层 + 15 [第四层第五个数前面和] = 21
然后讲上述思路转换为编程思路:
分层解决问题,把内容模块化,然后逐个实现即可
- 估计层数 – (1+x)*x/ 2>=1e12 ==> x = 1500000层
- 所以1500000层可以容纳1e12个数,也可以用数组存下
- 关键公式:sum = 前缀和求ab中间层数的和 + a当前层后面几个数量 + b当前层前面几个数量
- 解决给定第n个数,求出他在第几层第几个数。
- 解决求中间层数
#include
#include
#define ll long long
using namespace std;
ll dp[1500000]; // 每一层的和
ll dpSum[1500000]; // 层的前缀和
/*int dp[30] = {0,1,1,2,1,2,3,1,2,3,4,1,2,3,4,5,1,2,3,4,5,6};
1 1
2 1 2
3 1 2 3
4 1 2 3 4
5 1 2 3 4 5
*/
//函数思路是找到a和b是第几层的第几个
//sum = 前缀和求ab中间层数的和 + a当前层后面几个数量 + b当前层前面几个数量
ll check(ll a,ll b){
ll temp = 1;
ll flag = 1;
while((temp+1)*(temp)/2 < a){
temp++;
}
ll aDeep = temp,aCnt = aDeep - (((aDeep+1)*(aDeep)/2) - a);
temp = 1;
flag = 1;
while((temp+1)*(temp)/2 < b){
temp++;
}
ll bDeep = temp,bCnt = bDeep - (((bDeep+1)*(bDeep)/2) - b);
ll sum = 0;
//cout << aDeep << ' ' << aCnt << ' ' << bDeep << ' ' << bCnt << endl;
if(bDeep > aDeep)
sum = dpSum[bDeep-1] - dpSum[aDeep];
if(bDeep > aDeep){
sum += (aDeep+aCnt)*(aDeep+1-aCnt)/2;
sum += (1+bCnt)*(bCnt+1-1)/2;
}else{
sum += (aCnt + bCnt)*(bCnt + 1 - aCnt)/2;
}
return sum;
}
int main(){
dp[0] = 0;
dpSum[0] = 0;
//推算到 1500000层正好大约1e12次方个数
//处理1500000层的数据
for(int i = 1; i <= 1500000; i++){
dp[i] = dp[i-1] + i;
dpSum[i] = dpSum[i-1] + dp[i];
}
//输入数据
ll n;
cin >> n;
for(ll i = 0; i < n; i++){
ll a, b;
cin >> a >> b;
cout << check(a,b) << endl;
}
return 0;
}
时间限制: 1.0s 内存限制: 256.0MB
小蓝有一个 01 串 s = s1 s2 s3 · · · sn。
以后每个时刻,小蓝要对这个 01 串进行一次变换。每次变换的规则相同。对于 01 串 s = s1 s2 s3 · · · sn,变换后的 01 串 s′ = s′1 s′2 s′3 · · · s′_n _为:
s′1 = s1;
s′_i _= si−1 ⊕ si 。
其中 _a _⊕ _b _表示两个二进制的异或,当 _a _和 _b _相同时结果为 0,当 _a _和 b
不同时结果为 1。
请问,经过 _t _次变换后的 01 串是什么?
【输入格式】
输入的第一行包含两个整数 n, t,分别表示 01 串的长度和变换的次数。第二行包含一个长度为 _n _的 01 串。
【输出格式】
输出一行包含一个 01 串,为变换后的串。
【样例输入】
5 3
10110
【样例输出】
11010
【样例说明】
初始时为 10110,变换 1 次后变为 11101,变换 2 次后变为 10011,变换 3
次后变为 11010。
【评测用例规模与约定】
对于 40% 的评测用例,1 ≤ _n _≤ 100, 1 ≤ _t _≤ 1000。
对于 80% 的评测用例,1 ≤ _n _≤ 1000, 1 ≤ _t _≤ 109。
对于所有评测用例,1 ≤ _n _≤ 10000, 1 ≤ _t _≤ 1018。
map记录第几个是那种样子
set标记,第二次遇上就退出循环
//变异
#include
#include
#define ll long long
using namespace std;
map<ll,string> m;
set<string> s;
int main(){
ll len,cnt,cntTemp;
cin >> len >> cnt;
cntTemp = cnt;
string str;
cin >> str;
ll flag = 0;
while(cnt--){
string temp = str;
for(int i = 1; i < len; i++){
temp[i] = (str[i-1]-'0')^(str[i]-'0') + '0';
}
//cout << temp << endl;
if(s.count(temp) == 1){
//cout<< "提前循环";
break;
}
s.insert(temp);
flag += 1;
m[flag] = temp;
str = temp;
}
if(cnt < 0){
cout << str;
}else{
ll index = cntTemp % flag;
if(index == 0) index = flag;
cout<< m[index];
}
return 0;
}
时间限制: 1.0s 内存限制: 256.0MB
小蓝最近在学习二进制。他想知道 1 到 _N _中有多少个数满足其二进制表示中恰好有 _K _个 1。你能帮助他吗?
【输入格式】
输入一行包含两个整数 _N _和 K。
【输出格式】
输出一个整数表示答案。
【样例输入】
7 2
【样例输出】
3
【评测用例规模与约定】
对于 30% 的评测用例,1 ≤ _N _≤ 106, 1 ≤ _K _≤ 10。
对于 60% 的评测用例,1 ≤ _N _≤ 2 × 109, 1 ≤ _K _≤ 30。对于所有评测用例,1 ≤ _N _≤ 1018, 1 ≤ _K _≤ 50。
暴力循环遍历可以拿稳30%的
dfs找可以混60%的分
但考试最后没空写完另一种情况了,估计30%左右
#include
#include
#define ll long long
using namespace std;
// 60位数可以表示1e18
// dp / 搜索
int temp[60] = {
0},maxNum[60] = {
0};
int pos[60] = {
0}; //第几个i在哪个位置
string str;
ll N,K;
ll ans = 1;
int haveOne = 0,Cnt;
//第n个1
int find(int n){
for(int i = 0; i < Cnt; i++){
}
}
void dfs(int n){
if(n < 0) return;
int nowIndex = pos[n];
int tIndex = nowIndex + 1;
while(tIndex < Cnt && maxNum[tIndex] == 0){
swap(maxNum[tIndex],maxNum[nowIndex]);
ans++;
dfs(n-1);
swap(maxNum[tIndex],maxNum[nowIndex]);
tIndex++;
}
dfs(n-1);
}
int main(){
cin >> N >> K;
Cnt = 0;
while(N){
temp[Cnt++] = N % 2;
N/=2;
}
for(int i = 0; i < Cnt; i++){
maxNum[i] = temp[Cnt - 1 - i];
if(maxNum[i] == 1){
pos[haveOne++] = i;
}
//cout << maxNum[i] << endl;
}
//已有的大于需要的就舍去后面的1
if(haveOne > K){
int flag = haveOne - K;
while(flag--){
for(int i = Cnt - 1; i >= 0; i--){
if(maxNum[i] == 1){
maxNum[i] = 0;
break;
}
}
}
}
else if(haveOne < K){
//已有的小于需要的就从前面补
int flag = K - haveOne;
while(flag--){
for(int i = 0; i < Cnt; i++){
if(maxNum[i] == 0){
maxNum[i] = 1;
pos[haveOne++] = i;
break;
}
}
}
}
haveOne = K;
/*for(int i = 0; i < haveOne; i++){
cout << pos[i];
}*/
dfs(haveOne-1);
cout << ans;
return 0;
}
时间限制: 2.0s 内存限制: 512.0MB
给定一个长度为 _n _的括号序列,要求支持两种操作:
- 将 [Li, Ri] 区间内(序列中的第 Li 个字符到第 Ri 个字符)的括号全部翻转(左括号变成右括号,右括号变成左括号)。
- 求出以 _Li _为左端点时,最长的合法括号序列对应的 _Ri _(即找出最大的
Ri 使 [Li, Ri] 是一个合法括号序列)。
【输入格式】
输入的第一行包含两个整数 n, m,分别表示括号序列长度和操作次数。第二行包含给定的括号序列,括号序列中只包含左括号和右括号。
接下来 m 行,每行描述一个操作。如果该行为 “1 Li Ri”,表示第一种操作,区间为 [Li, Ri] ;如果该行为 “2 Li” 表示第二种操作,左端点为 Li。
【输出格式】
对于每个第二种操作,输出一行,表示对应的 Ri。如果不存在这样的 Ri,请输出 0。
【样例输入】
7 5
((())()
2 3
2 2
1 3 5
2 3
2 1
【样例输出】
4
7
0
0
【评测用例规模与约定】
对于 20% 的评测用例,n, _m _≤ 5000; 对于 40% 的评测用例,n, _m _≤ 30000;对于 60% 的评测用例,n, _m _≤ 100000;
对于所有评测用例,1 ≤ _n _≤ 106, 1 ≤ _m _≤ 2 × 105。
因为每次查都会浪费时间,而且用例很大,所以每次进行调转操作后,就记录每个点对应的匹配点在哪
此时又有一种情况()()() 此时的1 3 5都是以6截至,本来应该是12 34 56匹配,但题目是最远匹配处,所以要延申后面的匹配
所以看成正常匹配时fa[1] = 2,fa[2] = 0,fa[3] = 4,fa[4] = 6;
而当fa[1]匹配时查看匹配点2右边的点是否还继续匹配,
fa[1] + 1表示第一个匹配的括号的右边第一个位
fa[ fa[1] + 1 ]表示看下右边还有没有继续匹配的
匹配的话就继续延申下去,找到头,然后返回路上都
fa[1] == 2 fa[2+1]!=0 继续
fa[3] == 4 fa[4+1]!=0 继续
fa[5] == 6 fa[6] = 0 回退 return 6
fa[3] = 6
fa[1] = 6
置换就直接换就行
#include
#include
#define ll long long
using namespace std;
map<int ,int > mp;
string str;
int num[1000005];
int n,m;
//初始化
void init(){
mp.clear();
stack<int> sta;
for(int i = 1; i <=n ; i++){
if(num[i] == 1){
sta.push(i);
}else if(num[i] == 0 && sta.size()){
int index = sta.top();
if(index != 0){
sta.pop();
mp[index] = i;
}
}else if(num[i] == 0 && !sta.size()){
sta.push(0);
}
}
}
//改造的压缩并查集
int findFa(int a,int deep){
if(mp[a] == 0 && deep == 0){
return 0;
}
if(mp[a] == 0){
return a - 1;
}
mp[a] =findFa(mp[a]+1,deep+1);
return mp[a];
}
int main(){
cin >> n >> m;
cin >> str;
//处理输入变成01串,方便倒置 !str[i]就行
for(int i = 0;i < n; i++){
if(str[i] == '('){
num[i+1] = 1;
}else{
num[i+1] = 0;
}
}
init();
for(int i = 0; i < m; i++){
int flag;
cin >> flag;
//倒置
if(flag == 1){
int a,b;
cin >> a >> b;
for(int j = a; j <= b; j++){
num[j] = !num[j];
}
init();
}else{
//直接查询
int a;
cin >> a;
cout << findFa(a,0) << endl;
}
}
return 0;
}
时间限制: 1.0s 内存限制: 256.0MB
给定 T 个数 n1, n2, · · · , nT ,对每个 ni 请求出有多少组 a, b, c 满足:
- 1 ≤ a, b, c ≤ ni;
a ⊕ b ⊕ c = 0,其中 ⊕ 表示二进制按位异或;
长度为 a, b, c 的三条边能组成一个三角形。
【输入格式】
输入的第一行包含一个整数 T 。
接下来 T 行每行一个整数,分别表示 n1, n2, · · · , nT 。
【输出格式】
输出 T 行,每行包含一个整数,表示对应的答案。
【样例输入】
2
6
114514
【样例输出】
6
11223848130
【评测用例规模与约定】
对于 10% 的评测用例,T = 1, 1 ≤ ni ≤ 200;
对于 20% 的评测用例,T = 1, 1 ≤ ni ≤ 2000;对于 50% 的评测用例,T = 1, 1 ≤ ni ≤ 220;
对于 60% 的评测用例,1 ≤ T ≤ 100000, 1 ≤ ni ≤ 220;
对于所有评测用例,1 ≤ T ≤ 100000
没啥说的,能力不够,感觉蓝桥杯今年突然爱上了二进制和一些异或操作
i <= j <= k <= 2000三层遍历。
感觉应该先判断下T再预处理。。怕2000超时10%都拿不到。。失算了
#include
#include
#define ll long long
using namespace std;
int check(int a,int b,int c){
if(a == 0 || b == 0 || c == 0) return 0;
if(a + b <= c) return 0;
if(b + c <= a) return 0;
if(a + c <= b) return 0;
return 1;
}
int dp[300] = {
0};
int main(){
int n = 100;
ll ans = 1;
for(int i = 1; i <= n; i++){
for(int j = i; j <=n; j++){
for(int k = j; k <= n; k++){
int ji = i ^ j ^ k;
if(ji == 0 && check(i,j,k)){
//printf("%d %d %d %d\n",i,j,k,i^j^k);
dp[k]++;
}
}
}
}
for(int i = 1; i <= n; i++){
dp[i] = dp[i] + dp[i-1];
}
int T;
cin >> T;
while(T--){
int temp;
cin >> temp;
cout << dp[temp] * 6 << endl;
}
return 0;
}
感觉这次蓝桥杯怪怪的,反正打完也没啥太遗憾,感觉也没啥太大提升空间,一些会的就会,不会的二进制和贼大的数据也弄不动。除了填空题那个二叉树没写,然后最后没时间写二进制问题,其他都还行吧。。感觉去年下半年也拿了国二了,这次拿国二国三都无所谓了~。