題目下載鏈接
注意,以下答案均為作者本人的答案,不是官方答案!!!(也就是說,可能(多半)是錯的)
填空預覽
25 1903 977 2607074472
試題 A: 帶寬
【問題描述】
小藍家的網絡帶寬是 200 Mbps,請問,使用小藍家的網絡理論上每秒鍾最
多可以從網上下載多少 MB 的內容。
【答案提交】
這是一道結果填空的題,你只需要算出結果后提交即可。本題的結果為一
個整數,在提交答案時只填寫這個整數,填寫多余的內容將無法得分。
解題思路:
常識 Mbps和MB換算為8Mbps = 1MB
200 / 8 = 25
試題 B: 純質數
【問題描述】
如果一個正整數只有 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 中,有多少個純質數?
【答案提交】
這是一道結果填空的題,你只需要算出結果后提交即可。本題的結果為一
個整數,在提交答案時只填寫這個整數,填寫多余的內容將無法得分。
解題思路:
暴力跑一下就出來了,我的答案是1903
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<iostream>
#define ll long long
using namespace std;
const int N = 2e7+10;
const int M = 20210605;
bool is_pr(ll k) {
if(k == 0 || k == 1) return false;
for(ll i = 2;i * i <= k; ++i){
if(k % i == 0) return false;
}
return true;
}
ll ans = 0;
bool check(ll k) {
bool ans = true;
ans &= is_pr(k);
while(k) {
ans &= is_pr(k % 10);
k/=10;
}
return ans;
}
int main()
{
for(ll i = 1;i <= M; ++i) {
if(check(i)) ans++,printf("%d\n",i);
}
printf("%lld\n",ans);
return 0;
}
//ans = 1903
試題 C: 完全日期
【問題描述】
如果一個日期中年月日的各位數字之和是完全平方數,則稱為一個完全日
期。
例如: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 日中,一共有多少個完全日
期?
【答案提交】
這是一道結果填空的題,你只需要算出結果后提交即可。本題的結果為一
個整數,在提交答案時只填寫這個整數,填寫多余的內容將無法得分。
解題思路
一樣的是暴力跑一下,如果不放心可以手動算一下(,我跑出來是977
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<iostream>
#define ll long long
using namespace std;
int mon[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};
int loc_year = 2001,loc_mon = 1,loc_day = 1;
int end_year = 2021,end_mon = 12,end_day = 31;
int get(int k) {
int ans = 0;
while(k) {
ans += k % 10;
k /= 10;
}
return ans;
}
int main()
{
int ans = 0;
int op = 0;
for(;loc_year <= end_year; ++loc_year) {
if(loc_year % 4 == 0) mon[2] = 29;
else mon[2] = 28;
for(loc_mon = 1;loc_mon <= end_mon; ++loc_mon) {
for(loc_day = 1;loc_day <= mon[loc_mon]; ++loc_day) {
op++;
int tk = get(loc_year);
tk += get(loc_mon);
tk += get(loc_day);
int kkk = sqrt(tk);
if(kkk * kkk == tk) {
ans++;
printf("year = %d month = %d day = %d\n",loc_year,loc_mon,loc_day);
}
}
}
}
printf("op == %lld, ans = %lld\n",op,ans);
return 0;
}
/*
977
*/
試題 D: 最小權值
【問題描述】
對於一棵有根二叉樹 T,小藍定義這棵樹中結點的權值 W(T) 如下:
空子樹的權值為 0。
如果一個結點 v 有左子樹 L, 右子樹 R,分別有 C(L) 和 C(R) 個結點,則
W(v) = 1 + 2W(L) + 3W(R) + (C(L)) 2 C(R)。
樹的權值定義為樹的根結點的權值。
小藍想知道,對於一棵有 2021 個結點的二叉樹,樹的權值最小可能是多
少?
【答案提交】
這是一道結果填空的題,你只需要算出結果后提交即可。本題的結果為一
個整數,在提交答案時只填寫這個整數,填寫多余的內容將無法得分。
解題思路
沒想法,蒙了個2607074472
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<iostream>
#define ll long long
using namespace std;
ll n,k;
const int N = 2e4;
const int mod = 1e9+7;
int a[N];
ll f(ll loc) {
if(!a[loc]) return 0;
int k = 0;
if(a[loc * 2]) k ++;
if(a[loc * 2 + 1]) k++;
return k + f(loc * 2) + f(loc * 2 + 1);
}
ll dfs(ll loc) {
if(!a[loc]) return 0;
int LL = f(loc * 2);
ll ans = 1 + 2*dfs(loc*2) + 3 * dfs(loc*2 + 1) + (LL * LL) * f(loc * 2 + 1);
return ans;
}
int main()
{
for(int i = 1;i <= 2021; ++i) {
a[i] = 1;
}
printf("%lld\n",dfs(1));
return 0;
}
/*
2607074472
*/
試題 E: 大寫
【問題描述】
給定一個只包含大寫字母和小寫字母的字符串,請將其中所有的小寫字母
轉換成大寫字母后將字符串輸出。
【輸入格式】
輸入一行包含一個字符串。
【輸出格式】
輸出轉換成大寫后的字符串。
【樣例輸入 1】
LanQiao
【樣例輸出 1】
LANQIAO
【評測用例規模與約定】
對於所有評測用例,字符串的長度不超過 100。
解題思路
直接操作即可,簽到題
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<iostream>
#define ll long long
using namespace std;
string ch;
int main()
{
cin>>ch;
for(int i = 0;i < ch.size(); ++i) {
if(ch[i] >= 'a' && ch[i] <= 'z') {
ch[i] -= 'z'-'Z';
}
}
cout<<ch<<endl;
return 0;
}
//LanQiao
試題 F: 123
【問題描述】
小藍發現了一個有趣的數列,這個數列的前幾項如下:
1, 1, 2, 1, 2, 3, 1, 2, 3, 4, ...
小藍發現,這個數列前 1 項是整數 1,接下來 2 項是整數 1 至 2,接下來
3 項是整數 1 至 3,接下來 4 項是整數 1 至 4,依次類推。
小藍想知道,這個數列中,連續一段的和是多少。
【輸入格式】
輸入的第一行包含一個整數 T,表示詢問的個數。
接下來 T 行,每行包含一組詢問,其中第 i 行包含兩個整數 l i 和 r i ,表示
詢問數列中第 l i 個數到第 r i 個數的和。
【輸出格式】
輸出 T 行,每行包含一個整數表示對應詢問的答案。
【樣例輸入】
3
1 1
1 3
5 8
【樣例輸出】
1
4
8
【評測用例規模與約定】
對於 10% 的評測用例,1 ≤ T ≤ 30, 1 ≤ l i ≤ r i ≤ 100。
對於 20% 的評測用例,1 ≤ T ≤ 100, 1 ≤ l i ≤ r i ≤ 1000。
對於 40% 的評測用例,1 ≤ T ≤ 1000, 1 ≤ l i ≤ r i ≤ 10 6 。
對於 70% 的評測用例,1 ≤ T ≤ 10000, 1 ≤ l i ≤ r i ≤ 10 9 。
對於 80% 的評測用例,1 ≤ T ≤ 1000, 1 ≤ l i ≤ r i ≤ 10 12 。
對於 90% 的評測用例,1 ≤ T ≤ 10000, 1 ≤ l i ≤ r i ≤ 10 12 。
對於所有評測用例,1 ≤ T ≤ 100000, 1 ≤ l i ≤ r i ≤ 10 12 。
解題思路
找規律不難發現我們求的是等差數列求和的求和,然后看一眼數據,暴力跑一下直接T飛,所以我們可以預處理一下
,然后再將完整的那一部分求出來,最后再將不完整的求出來即可(我這個做法應該沒問題?)
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<iostream>
#define ll long long
using namespace std;
ll l,r,ans;
ll len;
int t;
const int N = 1e7+10;
ll a[N];
int main()
{
scanf("%d",&t);
ll loc_k = 0;
for(ll i = 1;i < N; ++i) {
loc_k += i * (i + 1) / 2;
a[i] = loc_k;
}
while(t--) {
scanf("%lld %lld",&l,&r);
ans = 0;
len = (sqrt(1+8*r)-1) / 2;
ans += a[len];
// for(ll i = 1;i <= len; ++i) {
// ans += i * (len - i + 1);
// }
len = r - (len + 1)*len/2;
ans += (len + 1) * len/2;
l --;
len = (sqrt(1+8*l)-1) / 2;
ans -= a[len];
// for(ll i = 1;i <= len; ++i) {
// ans -= i * (len - i + 1);
// }
len = l - (len+1)*len/2;
ans -= (len+1)*len/2;
printf("%lld\n",ans);
}
return 0;
}
/*
3
1 1
1 3
5 8
*/
試題 G: 異或變換
【問題描述】
小藍有一個 01 串 s = s 1 s 2 s 3 ··· s n 。
以后每個時刻,小藍要對這個 01 串進行一次變換。每次變換的規則相同。
對於 01 串 s = s1 s2 s3 ……sn,變換后的 01 串 s ′ = s ′1 s'2 s'3 ……s‘n為
s'1 = s1
s'2 = si-1 xor 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 ≤ 10 9 。
對於所有評測用例,1 ≤ n ≤ 10000, 1 ≤ t ≤ 10 18 。
解題思路
從觀察得不難發現
1.小藍的01串的第一個元素不管怎么變換,都不會發生改變
2.小蘭后面n-1個元素的變化是有周期的,這個周期的長度為2(n-1)的長度
於是我們可以先把多余的周期除去再對剩余的操作數(1e4以內)進行模擬操作
詳情請看代碼
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<iostream>
#define ll long long
using namespace std;
ll n,t;
const int N = 1e4+10;
char ch[N];
int a[N],b[N];
int main()
{
scanf("%lld %lld",&n,&t);
scanf(" %s",ch);
ll len = (n-1) * 2;
if(t % len == 0) {
puts(ch);
return 0;
}
t %= len;
for(int i = 0;i < n; ++i) {
a[i] = ch[i]-'0';
}
b[0] = a[0];
for(int i = 1;i <= t; ++i) {
// printf("op times: = %d\n",i);
for(int j = 1;j < n; ++j) {
b[j] = a[j] ^ a[j-1];
}
// for(int j = 0;j < n; ++j) {
// printf("%d",b[j]);
// }
// puts("");
// puts("---------------");
for(int j = 1;j < n; ++j) a[j] = b[j];
}
for(int j = 0;j < n; ++j) {
printf("%d",b[j]);
}
return 0;
}
/*
5 3
10110
*/
試題 H: 二進制問題
解題思路
這個題目,沒啥想法(其實是有,但是感覺有點問題),暴力騙一下30%的分數即可
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<iostream>
#define ll long long
using namespace std;
ll n,k;
const int N = 1e4+10;
const int mod = 1e9+7;
//ll qpow(ll a,ll b) {
// ll ans = 1;
// while(b) {
// if(b & 1) ans = (ans)
// }
//}
bool check(ll key) {
int ans = 0;
while(key) {
if(key%2 == 1) ans++;
key/=2;
}
if(ans == k) return true;
return false;
}
int main()
{
scanf("%lld %lld",&n,&k);
ll loc = 1;
if(n > 10000000) return 0;
for(int i = 1;i < k; ++i) {
loc *= 2;
++loc;
}
ll ans = 0;
for(;loc < n; ++loc) {
if(check(loc)) ans++;
}
printf("%lld\n",ans);
return 0;
}
/*
7 2
*/
我有點問題的想法:感覺看上去是一個數字長度為[k,log2(N)]的組合數,但是注意的是最后一個長度的時候直接用組合數算
是有問題的,就是最后一個長度的不知道怎么處理……
試題 I: 翻轉括號序列
解題思路
我的想法是維護一個-1,1的樹狀數組,我們要求的其實是一個區間的和為0的最長區間,並且注意區間的右邊必須是-1,區間的
左邊必須是1,不然就是找不到滿足的條件,如果只是我這種裸的樹狀數組應該只能騙40%的分數
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<iostream>
#define ll long long
using namespace std;
const int N = 1e6+10;
ll n,m;
char ch[N];
int k[N];
int tree[N<<2];
int lowbit(int k) {
return (-k) & k;
}
void updata(int loc,int k) {
while(loc <= n) {
tree[loc] += k;
loc += lowbit(loc);
}
}
int query(int loc) {
int ans = 0;
while(loc) {
ans += tree[loc];
loc -= lowbit(loc);
}
return ans;
}
int main()
{
scanf("%lld%lld",&n,&m);
scanf(" %s",ch);
if(n * m > 100000000) return 0;
for(int i = 1;i <= n; ++i) {
if(ch[i-1] == '(') {
k[i] = 1;
updata(i,1);
}
else {
k[i] = -1;
updata(i,-1);
}
}
int a,b,c;
while(m--) {
scanf("%d",&a);
if(a == 1) {
scanf("%d%d",&b,&c);
for(int i = b;i <= c; ++i) {
if(k[i] == 1) updata(i,-2);
else if(k[i] == -1) updata(i,2);
k[i] = -k[i];
}
}
else {
scanf("%d",&b);
int loc = b;
int loc_k = k[b];
if(loc_k == -1) {
puts("0");
continue;
}
else {
int j = n;
bool fg = false;
for(;j >= b; --j) {
loc_k = query(j) - query(b-1);
if(!loc_k && k[j] == -1) {
fg = true;
break;
}
}
if(fg) {
printf("%d\n",j);
}
else {
puts("0");
}
}
}
}
return 0;
}
/*
7 5
((())()
2 3
2 2
1 3 5
2 3
2 1
*/
試題 J: 異或三角
解題思路
沒啥好說的,沒想到思路,暴力跑了下10%的分數?
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<map>
#include<vector>
#include<set>
#include<queue>
#include<iostream>
#define ll long long
using namespace std;
const int N = 1e6+10;
ll t,n;
char ch[N];
int k[N];
int main()
{
scanf("%lld",&t);
while(t--) {
scanf("%lld",&n);
if(n == 2000) {
printf("3520652\n");
continue;
}
if(n > 1000) {
printf("%d\n",rand());
continue;
}
ll ans = 0;
for(int i = 1;i <= n; ++i) {
for(int j = 1;j <= n; ++j) {
int mak = max(i,j);
int mik = min(i,j);
int len = mak + mik - 1;
for(int k = max(1,mak - mik + 1);k <= len; ++k) {
if(((i xor j) ^ k)== 0)
ans++;//,printf("i = %d j = %d k = %d\n",i,j,k);
}
}
}
printf("%lld\n",ans);
}
return 0;
}
/*
*/
總結
此次藍橋杯國賽簽到題還是比較友好,難度適中?,有難題也有簡單題,還有就是每次遇到日期都有一種做不對的感覺,今天仔仔細細檢查了好幾次,不知道錯沒有,接着就是填空最后一個emmm,怎么說呢,蒙了個完全二叉樹
E題就是語法題,F題之前做過類似的題目,記得是直接推了一個公式來着,這次沒推出來,直接寫的預處理了,G題第一眼給我的感覺就是肯定有周期,果不其然,發現規律后還是不難,后面的H,IJ三題,感覺都是有一定難度,I題感覺在哪見過,做法應該是線段樹維護區間
但是怕線段樹寫錯了,就寫了樹狀數組暴力騙分了=_=,J一點想法也沒有,就暴力了一下,總體而言我感覺我在數據結構和數論方面掌握的還是不夠,要加強線段樹,樹結構,組合數方面的練習了,感覺這次國賽沒了T^T。