hdu 6146 Pokémon GO (計數)
今天它決定要抓住所有的精靈球!
為了不讓度度熊失望,精靈球已經被事先放置在一個2*N的格子上,每一個格子上都有一個精靈球。度度熊可以選擇任意一個格子開始遊戲,抓捕格子上的精靈球,然後移動到一個相鄰的至少有一個公共點的格子上繼續抓捕。 例如,(2, 2) 的相鄰格子有(1, 1), (2, 1) 和 (1, 2) 等等。
現在度度熊希望知道將所有精靈球都抓到並且步數最少的方案數目。 兩個方案被認為是不同,當且僅當兩個方案至少有一步所在的格子是不同的。 Input 第一行為T,表示輸入數據組數。 每組數據包含一個數N。
●1≤T≤100
●1≤N≤10000
一道計數問題,重點就是要做到不重不漏.
怎樣步數最短呢?當然是每個格子都只經過1次啦.
然後我們註意到如果這個起點選在中間的第i列,我們就把這個格子劃分成了左右兩個部分
感覺就是對於某個起點然後左右兩部分是之前求過的答案直接相乘,不同起點再相加就可以了,但是關鍵問題是我們怎樣計數呢?
我們設 Bn 代表從某個角(如左上角)出發,然後走遍所有格子回到同一列的方案數目。
同樣,我們設 An 代表從某個角出發,然後走遍所有格子的方案數。
下面我們來解釋這個式子
第一項表示從某個角開始最後回到起點的同一列的那個角
第二項表示從某個角開始,第二步走與起點相同列的那個角,第三步我們向第二列走的時候就有兩種走法了(選擇直接向右或者走對角線,乘的那個2)
從第四步開始我們現在面對的問題就是了
第三項中4可以看成2*2,
我們把前兩列寫成這個樣子
1 | 2 |
3 | 4 |
第一個2代表走一個(1 2 3 4)和(1 4 3 2)有兩種走法起點在第一列而終點在第二列
第二個2代表對於每一個到達第二列後第五步向第三列走的時候都有兩種走法(向右或者走對角線)
從第六步開始時我們面對的問題就是了
我們現在來考慮下正經問題
首先有4個角,那麽ans先加上
但是如果我們起點選在中間呢?
假設我們選在了第i列,首先這一列有兩個格子 所以先乘個2
現在我們可以選擇先往左跑,我們可以直接向左,也可以走一個向左的對角線.再乘個2
註意往左跑完1~i-1列以後一點要跑到第i列那個"不是起點的點"否則沒法往右跑,所以乘的是
現在我們又回到了第i列,現在我們向右跑,又有兩種情況,直接向右,向右的對角線 再乘個2
現在我們到了i+1列對於右半部分(i+1~n)我們只要跑完就行了,我們不關心終點所以乘
這樣一開始向左跑就是,一開始向右跑自然是
1 #include <bits/stdc++.h> 2 3 using namespace std; 4 typedef long long ll; 5 const int maxn = 11000; 6 const ll mod = 1e9+7; 7 ll a[maxn],b[maxn]; 8 void init() 9 { 10 b[1]=1; 11 for (int i=2;i<maxn;++i){ 12 b[i] = (b[i-1]*2)%mod; 13 } 14 a[1] = 1; 15 a[2] = 6; 16 for (int i=3;i<maxn;++i) 17 a[i] = (b[i]%mod+(2*a[i-1]%mod)+(4*a[i-2])%mod)%mod; 18 } 19 int n; 20 int main() 21 { 22 init(); 23 int T; 24 scanf("%d",&T); 25 while (T--){ 26 scanf("%d",&n); 27 if (n==1){ 28 printf("%d\n",2); 29 } 30 else{ 31 ll ans = 0; 32 ans = (a[n]*4)%mod; 33 for (int i=2;i<n;++i){ 34 ans = (ans+2*( ( ( (2*b[i-1])%mod) *( (2*a[n-i])%mod ) + ( (2*a[i-1])%mod) *( (2*b[n-i])%mod ) )%mod )%mod)%mod; 35 } 36 printf("%lld\n",ans); 37 } 38 } 39 return 0; 40 }
hdu 6146 Pokémon GO (計數)