藍橋杯 歷年試題 矩陣翻硬幣

2021-10-22 15:12:14 字數 3480 閱讀 1552

最近報名了藍橋杯,應該是我學習程式設計以來的第一場正式比賽了,最近就刷了一下歷年試題 這是其中比較有趣的題目,不過我的答案只有70%的分,想看正確**可以看這裡,沒過是演算法不太行,思路還是可以看看的。

小明先把硬幣擺成了乙個 n 行 m 列的矩陣。

隨後,小明對每乙個硬幣分別進行一次 q 操作。

對第x行第y列的硬幣進行 q 操作的定義:將所有第 ix 行,第 jy 列的硬幣進行翻轉。其中i和j為任意使操作可行的正整數,行號和列號都是從1開始。

當小明對所有硬幣都進行了一次 q 操作後,他發現了乙個奇蹟——所有硬幣均為正面朝上。

小明想知道最開始有多少枚硬幣是反面朝上的。於是,他向他的好朋友小m尋求幫助。

聰明的小m告訴小明,只需要對所有硬幣再進行一次q操作,即可恢復到最開始的狀態。然而小明很懶,不願意照做。於是小明希望你給出他更好的方法。幫他計算出答案。

首先,對於乙個硬幣,如果翻了奇數次後正面向上,則說明它一開始是反面朝上的,偶數反之,故題目就是叫我們求對所有硬幣進行了q操作後有多少個硬幣是翻了奇數次的。

然後,對q操作進行分析。q操作是

將所有第 i*x 行,第 j *y 列的硬幣進行翻轉。其中i和j為任意使操作可行的正整數,行號和列號都是從1開始

看上去有點像埃氏篩,盲猜和約數有關,然後按題意模擬一下n = 4 ,m = 6 的情況,用陣列a[i][j],存一下結果,以下是模擬結果。

122

3242

4464

8244

6483

6696

12

從模擬發現

1)a[i][j] = a[i][1] * a[1][j]

2)a[1][j] = j的約數個數,a[i][1] = i的約數個數

這個具體證明我就不寫了。因為我們只要知道奇偶關係,所以可以考慮用1帶表奇數,0帶表偶數,將a[i][j] 裡的值都用01替換掉後就將題目轉換為求所有值的和了。因為a[i][j] = a[i][1] * a[1][j](將值替換後這規律依舊沒變),所以全部資料的和可以用(a[1][1] +a[2][1] +…a[n][1])*(a[1][1]+a[1][2]+…a[1][m]) 表示。

因為用01替換了奇偶,所以(a[1][1] +a[2][1] +…a[n][1])就是a[i][1] 中奇數個數,結合發現1,問題轉化為:求1到m中,有幾個數的約數是奇數。乙個數的約數是成對出現的,如果是k是j的約數則j/k也是,約數是奇數個,說明j存在乙個約數k使k = j/k ,即j是平方數,所以問題又轉換為:1到m有幾個平方數,思考即可得答案為[sqrt(m)] (m的平方根向下取整)

所以最終答案就是m的平方根向下取整乘以n的平方根向下取整

本以為到這裡就完了,沒想到只是另乙個開始,資料範圍是1000位數,然後算平方根。。。你這是難為剛學程式設計的我啊,我用了一下高精度加二分,然後稍微優化,過了70%,以下是帶碼:

#include

#include

#include

#include

#include

using

namespace std;

vector<

int>a,b,c,mid2,d,e;

void

print

(vector<

int>

& a)

intcom

(vector<

int>

& a,vector<

int>

& b)

//高精度除以低精度 a/b=c...r a>=0,b>0

vector<

int>

div(vector<

int>

& a,

int b,

int& r)

reverse

(c.begin()

,c.end()

);while

(c.size()

>

1&&c.

back()

==0)c.pop_back()

;return c;

}//高精度加法 c=a+b a>=0,b>=0

vector<

int>

add(vector<

int>

& a,vector<

int>

& b)

// printf("ans=");print(k);printf("\n");

return k;

}//高精度乘以低精度 c=a*b a>=0,b>=0

vector<

int>

mul(vector<

int>

& a,

int b)

while

(c.size()

>

1&&c.

back()

==0)c.pop_back()

;return c;

}//高精度乘以高精度 c=a*b a>=0,b>=0,a.size()==b.size()

vector<

int>

mul(vector<

int>

&a,vector<

int>

&b)while

(c.size()

>

1&&c.

back()

==0)c.pop_back()

;return c;

}//高精度減法 c=a-b a>=b,a>=0,b>=0

vector<

int>

sub(vector<

int>

& a,vector<

int>

& b)

while

(c.size()

>

1&&c.

back()

==0)c.pop_back()

;return c;

}vector<

int>

vsqrt

(vector<

int>

& a)

else

// printf("%d %d\n",l.size(),r.size());

// print(l);

one.

push_back(1

);while

(com

(r,l)==1

)if(com

(r,l)==1

)return mid;

c=sub

(r,one)

; mid2=

mul(c,c)

;while

(com

(mid2,a)!=1

)return

sub(c,one);}

intmain()

藍橋杯歷年試題 矩陣翻硬幣

問題描述 小明先把硬幣擺成了乙個 n 行 m 列的矩陣。隨後,小明對每乙個硬幣分別進行一次 q 操作。對第x行第y列的硬幣進行 q 操作的定義 將所有第 i x 行,第 j y 列的硬幣進行翻轉。其中i和j為任意使操作可行的正整數,行號和列號都是從1開始。當小明對所有硬幣都進行了一次 q 操作後,他...

藍橋杯 矩陣翻硬幣

問題描述 小明先把硬幣擺成了乙個 n 行 m 列的矩陣。隨後,小明對每乙個硬幣分別進行一次 q 操作。對第x行第y列的硬幣進行 q 操作的定義 將所有第 i x 行,第 j y 列的硬幣進行翻轉。其中i和j為任意使操作可行的正整數,行號和列號都是從1開始。當小明對所有硬幣都進行了一次 q 操作後,他...

藍橋杯 矩陣翻硬幣

歷屆試題 矩陣翻硬幣 時間限制 1.0s 記憶體限制 256.0mb 問題描述 小明先把硬幣擺成了乙個 n 行 m 列的矩陣。隨後,小明對每乙個硬幣分別進行一次 q 操作。對第x行第y列的硬幣進行 q 操作的定義 將所有第 i x 行,第 j y 列的硬幣進行翻轉。其中i和j為任意使操作可行的正整數...