最近報名了藍橋杯,應該是我學習程式設計以來的第一場正式比賽了,最近就刷了一下歷年試題 這是其中比較有趣的題目,不過我的答案只有70%的分,想看正確**可以看這裡,沒過是演算法不太行,思路還是可以看看的。
小明先把硬幣擺成了乙個 n 行 m 列的矩陣。首先,對於乙個硬幣,如果翻了奇數次後正面向上,則說明它一開始是反面朝上的,偶數反之,故題目就是叫我們求對所有硬幣進行了q操作後有多少個硬幣是翻了奇數次的。隨後,小明對每乙個硬幣分別進行一次 q 操作。
對第x行第y列的硬幣進行 q 操作的定義:將所有第 ix 行,第 jy 列的硬幣進行翻轉。其中i和j為任意使操作可行的正整數,行號和列號都是從1開始。
當小明對所有硬幣都進行了一次 q 操作後,他發現了乙個奇蹟——所有硬幣均為正面朝上。
小明想知道最開始有多少枚硬幣是反面朝上的。於是,他向他的好朋友小m尋求幫助。
聰明的小m告訴小明,只需要對所有硬幣再進行一次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為任意使操作可行的正整數...