還記得noip2011的尋寶嗎?6年之後,小明帶著他的妹子小芳,再次走上了尋寶的道路。
然而這次他們尋寶回來之後,小明被困在了乙個迷宮中。
迷宮是乙個n*m的字元矩陣。
小明在這個矩陣的左上角,只能向下和向右走,去和在矩陣右下角的小芳會合。
小明必須將他走過的路徑上的,經過的字元收集起來。如果到右下角時他收集到的這些字元連在一起是回文的,那麼他就能夠走出這個迷宮,否則他就會掉進陷阱出不來。
小明想知道有多少條路徑能夠讓他走出這個迷宮。由於答案可能很大,請對1000000007取模。
輸入格式:
第一行兩個整數n和m。
接下來n行,每行m個字元表示這個矩陣,全部均為小寫字母
輸出格式:
輸出一行乙個整數表示答案
輸入樣例#1:
3 4aaab
baaa
abba
輸出樣例#1:
3
對於20%的資料,滿足n∗m≤10
對於另外10%的資料,滿足字元都是a
對於70%的資料,滿足n,m≤60
對於100%的資料,滿足n,m≤500
分析:一道比較考驗基本功的dp題.
看到題面就應該能想到狀態該怎麼表示了,設f[i][j][k][l]表示小明走到了(i,j),小芳走到了(k,l)的方案數,那麼該怎麼轉移呢?顯然不能順著推,因為不知道走過的字串是啥,如果記錄的話會有後效性,那麼根據回文字串的特點,小明從起點走,小芳從終點走,如果兩個人所在地方的字元是一樣的才能繼續走,直到兩個人碰面,答案累加,因為空間問題可以過70分.
後30%的資料只能開下500*500的陣列,也就是說我們只能夠儲存兩維.那麼我們可以儲存j和l,列舉當前走了多少步,因為方向一定,所以i和k能夠推導出來。因為只儲存了列的情況,如果直接推的話會計算重複,那麼再開乙個陣列g,記錄前一步的狀態,f從g轉移而來就可以了.
最後統計答案,如果n+m-1是奇數,那麼最後匯合的地點一定是同一行,否則有可能是同一行,也有可能相差一行.
總結:這一類dp問題特徵就是給你乙個n*m的圖,規定走的方向,讓你求某些值.狀態表示比較有規律,一般就是設f[i][j]表示走到了(i,j)的答案.如果題目變通一下讓你走兩次,那麼可以開四維陣列來表示狀態.有時候也需要變通一下列舉的順序,依題目而定,規定了走的方向,我們可以只用儲存3維就可以推出第4維,可以優化時間,我們也可以儲存2維,這樣就需要乙個輔助陣列記錄上一步的狀態,既優化了時間,也優化了空間.
#include #include#include
#include
#include
using
namespace
std;
const
int mod = 1000000007
;int n, m,f[510][510],g[510][510
];int dx[4] = , dy[4] = ;
long
long ans = 0
;char s[510][510
];int
main()
for (int i = 1; i <= m; i++)
for (int j = 1; j <= m; j++)
if(g[i][j])}}
}if ((n + m - 1) & 1
)
else
}printf(
"%d\n
", ans);
return0;
}
noip模擬賽 密碼
表示沒看懂演算法3 問題描述 有壓迫,就有反抗。mored的寵物在法庭的幫助下終於反抗了。作為乙隻聰明的寵物,他打算把魔法使mored的魔法書盜去,奪取mored的魔法能力。但mored怎麼會讓自己的魔法書輕易地被盜取?mored在魔法書上設定了乙個密碼鎖,密碼鎖上有乙個問題。施以斯臥鋪魔法吧,你有...
NOIP模擬賽 老師
題目描述 一座有n層的教學樓裡有一些學生,第i 0 i n 層有studentsi個學生。你被給定了乙個數k,如果第i層有x個學生,那麼這一層需要 x k 個老師。你可以調整每個學生的樓層,但是每個學生至多只能調整一層,就是說第i層的學生只能去第i 1層 如果有的話 第i層 第i 1層 如果i 1 ...
NOIP模擬賽 分錢
題目描述 兩個人在街上撿到了一些錢,這些錢共有n張,他們等了很久也沒有等來失主,於是決定把錢平分。但錢可能無法平分。他們先把能夠平分的錢盡量先平分了,使得剩下不能平分的錢盡量少。這些不能平分的錢怎麼辦呢他?他們決定拿去賭場裡面賭一把。他們運氣太好了,那些不能平分的錢變成了雙倍,於是他們就把那個錢分了...