2019第十屆藍橋杯C/C++語言A組題目及解析

這個題解是按照我自己的思路來的,沒有特別多的測試數據,也沒有官方正確的題解,若有錯誤望大佬指正。    

  A:平方和

【問題描述】
       小明對數位中含有 2、0、1、9 的數字很感興趣,在 1 到 40 中這樣的數包括 1、2、9、10 至 32、39 和 40,共 28 個,他們的和是 574,平方和是 14362。注意,平方和是指將每個數分別平方後求和。
請問,在 1 到 2019 中,所有這樣的數的平方和是多少?

【題目思路】

      直接暴力判斷就行

【答案】2658417853

#include<bits/stdc++.h>
using namespace std;
bool check(int num){
	while(num){
		if(num%10==2||num%10==0||num%10==1||num%10==9) return true;
		num/=10;
	}
	return false;
}
long long ans=0;
int main()
{
	for(int i=1;i<=2019;i++){
		if(check(i)) ans+=i*i;
	}
	cout<<ans<<endl;
	return 0;
 } 

      B.數列求值

【問題描述】
       給定數列 1, 1, 1, 3, 5, 9, 17, …,從第 4 項開始,每項都是前 3 項的和。求
第 20190324 項的最後 4 位數字。

【題目思路】直接暴力遞推就行,每次都mod10000

【答案】4659

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int a=1,b=1,c=1,d;
	for(int i=4;i<=20190324;i++){
		d=(a+b+c)%10000;
		a=b;b=c;c=d;
	}
	cout<<d<<endl;
	return 0;
}

    C. 最大降雨量

【問題描述】

        由於沙之國長年乾旱,法師小明準備施展自己的一個神祕法術來求雨。這個法術需要用到他手中的 49 張法術符,上面分別寫着 1 至 49 這 49 個數字。法術一共持續 7 周,每天小明都要使用一張法術符,法術符不能重複使用。每週,小明施展法術產生的能量爲這周 7 張法術符上數字的中位數。法術施展完 7 周後,求雨將獲得成功,降雨量爲 7 周能量的中位數。由於乾旱太久,小明希望這次求雨的降雨量儘可能大,請大最大值是多少?

【題目思路】

         這個題並不用寫代碼,還有就是要注意題目中的最大降雨量爲七週每週中位數的中位數,並不是求和

每週降水量從大到小排序,然後每週的中位數從大到小排序,那麼第四周第四天的法術符的數字就是本週的總降水量,那麼可以確定的是紅色部分一定比X大,那麼比X大的最少有15個,則X最大爲49-15=34.

等下再更

(幾個小時之後。。。)我回來了,出成績了,省二,省二第四名,差一點進決賽了,感覺有點遺憾。

D.迷宮

【問題描述】

下圖給出了一個迷宮的平面圖,其中標記爲 1 的爲障礙,標記爲 0 的爲可 以通行的地方。

010000

000100

001001

110000

迷宮的入口爲左上角,出口爲右下角,在迷宮中,只能從一個位置走到這 個它的上、下、左、右四個方向之一。 對於上面的迷宮,從入口開始,可以按DRRURRDDDR 的順序通過迷宮, 一共 10 步。其中 D、U、L、R 分別表示向下、向上、向左、向右走。 對於下面這個更復雜的迷宮(30 行 50 列),請找出一種通過迷宮的方式, 其使用的步數最少,在步數最少的前提下,請找出字典序最小的一個作爲答案。 請注意在字典序中D<L<R<U。

【題目給出的數據】

01010101001011001001010110010110100100001000101010
00001000100000101010010000100000001001100110100101
01111011010010001000001101001011100011000000010000
01000000001010100011010000101000001010101011001011
00011111000000101000010010100010100000101100000000
11001000110101000010101100011010011010101011110111
00011011010101001001001010000001000101001110000000
10100000101000100110101010111110011000010000111010
00111000001010100001100010000001000101001100001001
11000110100001110010001001010101010101010001101000
00010000100100000101001010101110100010101010000101
11100100101001001000010000010101010100100100010100
00000010000000101011001111010001100000101010100011
10101010011100001000011000010110011110110100001000
10101010100001101010100101000010100000111011101001
10000000101100010000101100101101001011100000000100
10101001000000010100100001000100000100011110101001
00101001010101101001010100011010101101110000110101
11001010000100001100000010100101000001000111000010
00001000110000110101101000000100101001001000011101
10100101000101000000001110110010110101101010100001
00101000010000110101010000100010001001000100010101
10100001000110010001000010101001010101011111010010
00000100101000000110010100101001000001000000000010
11010000001001110111001001000011101001011011101000
00000110100010001000100000001000011101000000110011
10101000101000100010001111100010101001010000001000
10000010100101001010110000000100101010001011101000
00111100001000010000000110111000000001000000001011
10000001100111010111010001000110111010101101111000

【題目思路】BFS搜索,記錄每一步是有上一步怎麼走過來的,又因爲需要字典序最小所以要按照字典序選擇路徑。

唉~當時對BFS記錄路徑不是很熟悉,拿啓發式DFS算法寫的,實在是慢,最後也沒得出答案。要是之前多寫一下搜索可能就進決賽了

【答案】DDDDRRURRRRRRDRRRRDDDLDDRDDDDDDDDDDDDRDDRRRURRUURRDDDDRDRRRRRRDRRURRDDDRRRRUURUUUUUUULULLUUUURRRRUULLLUUUULLUUULUURRURRURURRRDDRRRRRDDRRDDLLLDDRRDDRDDLDDDLLDDLLLDLDDDLDDRRRRRRRRRDDDDDDRR


#include<bits/stdc++.h>
using namespace std;
struct state{
	int x,y;
	state(int x_,int y_){
		x=x_;y=y_;
	}
};
int h,w;
int e[70][70],book[70][70],from[70][70];
int mo[4][2]={{1,0},{0,-1},{0,1},{-1,0}};
int inv_mo[4][2]={-1,0,0,1,0,-1,1,0};
char mo_ch[4]={'D','L','R','U'};
void input(){
	h=30;w=50;
	for(int i=0;i<h;i++){
		string s;cin>>s;
		for(int j=0;j<w;j++){
			e[i][j]=s[j]-'0';
		}
	}
}

void bfs(){
	queue<state>q;
	q.push(state(0,0));
	from[0][0]=-1;
	book[0][0]=1;
	while(!q.empty()){
		state temp=q.front();q.pop();
		if(temp.x==h-1&&temp.y==w-1) break;
		for(int i=0;i<4;i++){
			int nx=temp.x+mo[i][0];int ny=temp.y+mo[i][1];
			
			if(nx<0||ny<0||nx>=h||ny>=w||e[nx][ny]==1||book[nx][ny]) continue;
			
			book[nx][ny]=1;
			from[nx][ny]=i; //表示 nx ny 點是有上一個點通過第i個轉移到達的
			q.push(state(nx,ny)); 
		}
	}
}

void solve(){
	vector<char>v;
	int x=h-1,y=w-1;
	while(from[x][y]!=-1){
		v.push_back(mo_ch[from[x][y]]);
		int temp=from[x][y];
		x+=inv_mo[temp][0];
		y+=inv_mo[temp][1];
	}
	
	for(int i=v.size()-1;i>=0;i--){
		printf("%c",v[i]);
	}
}
int main()
{
	input();
	bfs();
	solve();
	return 0;
 } 

E: RSA 解密

【問題描述】
RSA 是一種經典的加密算法。它的基本加密過程如下。
      首先生成兩個質數 p, q,令 n = p · q,設 d 與 (p − 1) · (q − 1) 互質,則可找到 e 使得 d · e 除 (p − 1) · (q − 1) 的餘數爲 1。n, d, e 組成了私鑰,n, d 組成了公鑰。當使用公鑰加密一個整數 X 時(小於 n),計算 C = Xd mod n,則 C 是加密後的密文。
當收到密文 C 時,可使用私鑰解開,計算公式爲 X = Ce mod n。例如,當 p = 5, q = 11, d = 3 時,n = 55, e = 27。若加密數字 24,得 243 mod 55 = 19。解密數字 19,得 1927 mod 55 = 24。現在你知道公鑰中 n = 1001733993063167141, d = 212353,同時你截獲了別人發送的密文 C = 20190324,請問,原文是多少?

【解題思路】求n的兩個質數p,q

                      求e,然後按照上面的公式求就行了,用到快速乘,快速冪來優化一下。

這個代碼正確性應該是對的。。。但是太慢了,有大佬有好的方法教教我吧

#include<bits/stdc++.h>
using namespace std;
long long n,p,q,e,c,k,X,d;

long long fast_mul(long long x,long long d,long long mod){
	long long ans=0;
	x%=mod;d%=mod;
	while(d){
		if(d&1) ans=(ans+x)%mod;
		x<<=1;
		x%=mod;
		d>>=1;
	}
	return ans;
}

long long fast_pow(long long x,long long d,long mod){
	long long ans=1;
	x%=mod;
	while(d){
		if(d&1) ans=fast_mul(ans,x,mod);
		x=fast_mul(x,x,mod);
		d>>=1;
	}	
	return ans;
}
int main()
{
	n=1001733993063167141;
	d=212353;c=20190324;
	for(long long i=2;i<n;i++){
		if(n%i==0) {
			q=i;
			p=n/q;
			break;
		}
	}
	printf("p=%lld   q=%lld\n",p,q);
	k=(p-1)*(q-1);
	for(e=1;;e++){
		if(fast_mul(d,e,k)==1) break;
	}
	printf("e=%lld\n",e);
	
	X=fast_pow(c,e,n);
	printf("x=%lld\n",X);
	return 0;
}

試題 F: 完全二叉樹的權值

【問題描述】
給定一棵包含 N 個節點的完全二叉樹,樹上每個節點都有一個權值,按從上到下、從左到右的順序依次是 A1, A2, · · · AN
現在小明要把相同深度的節點的權值加在一起,他想知道哪個深度的節點權值之和最大?如果有多個深度的權值和同爲最大,請你輸出其中最小的深度。
注:根的深度是 1。
【輸入格式】
第一行包含一個整數 N。
第二行包含 N 個整數 A1, A2, · · · AN 。
【輸出格式】
輸出一個整數代表答案。
【樣例輸入】
7
1 6 5 4 3 2 1

【樣例輸出】
2

【題目思路】變輸入邊處理 第i個節點在深度 lon2(i)層上;然後找到最大的那個就行了。

#include<bits/stdc++.h>
using namespace std;
int sum[1000];
int n,x;
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>x;
		int temp=log2(i)+1;
		sum[temp]+=x;
	}
	int temp=log2(n)+1;
	int max_v=sum[1],Min=1;
	for(int i=1;i<=temp;i++){
		if(sum[i]>max_v){
			Min=i;
			max_v=sum[i];
		}
	}
	
	cout<<Min<<endl;
	return 0;
}

 

試題 G: 外賣店優先級

【問題描述】
“飽了麼”外賣系統中維護着 N 家外賣店,編號 1 ∼ N。每家外賣店都有一個優先級,初始時 (0 時刻) 優先級都爲 0。
每經過 1 個時間單位,如果外賣店沒有訂單,則優先級會減少 1,最低減到 0;而如果外賣店有訂單,則優先級不減反加,每有一單優先級加 2。
如果某家外賣店某時刻優先級大於 5,則會被系統加入優先緩存中;如果優先級小於等於 3,則會被清除出優先緩存。
給定 T 時刻以內的 M 條訂單信息,請你計算 T 時刻時有多少外賣店在優先緩存中。
【輸入格式】
第一行包含 3 個整數 N、M 和 T 。
以下 M 行每行包含兩個整數 ts 和 id,表示 ts 時刻編號 id 的外賣店收到一個訂單。
【輸出格式】
輸出一個整數代表答案。
【樣例輸入】
2 6 6
1 1
5 2
3 1
6 2
2 1
6 2

【樣例輸出】
1

【題目思路】將訂單按照時間排序,然後模擬

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100005;
struct Order{
	int time,id;
	Order(int time_,int id_){
		time=time_;id=id_; 
	}
	bool operator<(const Order& rhs)const{
		return rhs.time<time; 
	}
};
int sum[maxn],book[maxn];
int N,M,T,t,id;
int main()
{
	priority_queue<Order>q;
	cin>>N>>M>>T;
	while(M--){
		cin>>t>>id;
		q.push(Order(t,id));
	}
	int ans=0;
	while(!q.empty()){
		Order temp=q.top();q.pop();
		id=temp.id;
		for(int i=1;i<=N;i++){
			if(i==id) continue;
			if(sum[i]>0) sum[i]--;
			if(book[i]&&sum[i]<=3){
				book[i]=0;
				ans--;
			}
		}
		
		sum[id]+=2;
		if(!book[id]&&sum[id]>5){
			book[id]=1;
			ans++;
		}
	}
	
	cout<<ans<<endl;
	return 0;
}

試題 H: 修改數組

【問題描述】
給定一個長度爲 N 的數組 A = [A1, A2, · · · AN],數組中有可能有重複出現的整數。
現在小明要按以下方法將其修改爲沒有重複整數的數組。小明會依次修改
A2, A3, · · · , AN。
當修改 Ai 時,小明會檢查 Ai 是否在 A1 ∼ Ai−1 中出現過。如果出現過,則小明會給 Ai 加上 1 ;如果新的 Ai 仍在之前出現過,小明會持續給 Ai 加 1 ,直到 Ai 沒有在 A1 ∼ Ai−1 中出現過。
當 AN 也經過上述修改之後,顯然 A 數組中就沒有重複的整數了。現在給定初始的 A 數組,請你計算出最終的 A 數組。
【輸入格式】
第一行包含一個整數 N。
第二行包含 N 個整數 A1, A2, · · · , AN 。
【輸出格式】
輸出 N 個整數,依次是最終的 A1, A2, · · · , AN。
【樣例輸入】
5
2 1 1 3 4

【樣例輸出】
2 1 3 4 5

【題目思路】我是直接暴力寫的,看學長(下面有大佬學長的blog)的題解說是可以用並查集,會了一定回來更新

#include<bits/stdc++.h>
using namespace std;
int main()
{
	set<int>s;
	vector<int>v;
	int n, x;
	cin>>n;
	while(n--){
		cin>>x;
		while(s.count(x)) x++;
		s.insert(x);
		v.push_back(x);
	}
	
	for(int i=0;i<v.size();i++) printf("%d ",v[i]);
	return 0;
}

【問題描述】
糖果店的老闆一共有 M 種口味的糖果出售。爲了方便描述,我們將 M 種口味編號 1 ∼ M。
小明希望能品嚐到所有口味的糖果。遺憾的是老闆並不單獨出售糖果,而 是 K 顆一包整包出售。
幸好糖果包裝上註明了其中 K 顆糖果的口味,所以小明可以在買之前就知道每包內的糖果口味。
給定 N 包糖果,請你計算小明最少買幾包,就可以品嚐到所有口味的糖果。

【輸入格式】
第一行包含三個整數 N、M 和 K。
接下來 N 行每行 K 這整數 T1, T2, · · · , TK,代表一包糖果的口味。
【輸出格式】
一個整數表示答案。如果小明無法品嚐所有口味,輸出 −1。
【樣例輸入】
6 5 3
1 1 2
1 2 3
1 1 3
2 3 5
5 4 2
5 1 2

【樣例輸出】
2

【題目思路】狀壓dp,當時想到dp,但是最後還是沒想出來怎麼個dp法,然後直接拿搜索寫的,能過小數的樣例。

不準備把自己寫的代碼貼在上面了,實在是太蠢了。等把dp的代碼寫了回來再貼。

試題 J: 組合數問題

時間限制: 1.0s 內存限制: 256.0MB 本題總分:25 分

【問題描述】
給 n, m, k, 求 有 多 少 對 (i, j) 滿 足 1 ≤ i ≤ n, 0 ≤ j ≤ min(i, m) 且 C j ≡
0(mod k),k 是質數。其中 C j 是組合數,表示從 i 個不同的數中選出 j 個組成
一個集合的方案數。
【輸入格式】
第一行兩個數 t, k,其中 t 代表該測試點包含 t 組詢問,k 的意思與上文中相同。
接下來 t 行每行兩個整數 n, m,表示一組詢問。
【輸出格式】
輸出 t 行,每行一個整數表示對應的答案。由於答案可能很大,請輸出答案除以 109 + 7 的餘數。
【樣例輸入】
1 2
3 3
【樣例輸出】
1
【樣例說明】
在所有可能的情況中,只有 C1 = 2 是 2 的倍數。
【樣例輸入】
2 5

4 5
6 7

【樣例輸出】
0
7

【樣例輸入】
3 23
23333333 23333333
233333333 233333333
2333333333 2333333333

【樣例輸出】
851883128
959557926
680723120

不會,當時直接放棄了。。。

遼寧賽區第一學長的題解,掛上膜拜一下

https://blog.csdn.net/qq_36306833/article/details/88787806

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章