題目描述
小l有一座環形花園,沿花園的順時針方向,他把各個花圃編號為1~n(2<=n<=10^15)。他的環形花園每天都會換乙個新花樣,但他的花園都不外乎乙個規則,任意相鄰m(2<=m<=5,m<=n)個花圃中有不超過k(1<=k
例如,n=10,m=5,k=3。則
ccpcppppcc 是一種不符合規則的花圃;
ccppppcpcp 是一種符合規則的花圃。
請幫小l求出符合規則的花園種數mod 1000000007
由於請您編寫乙個程式解決此題。
輸入輸出格式
輸入格式:
一行,三個數n,m,k。
輸出格式:
花園種數mod 1000000007
輸入輸出樣例
輸入樣例#1: 複製
【樣例輸入1】
10 5 3
【樣例輸入2】
6 2 1
輸出樣例#1: 複製
【樣例輸出1】
458【樣例輸出2】
18說明
【資料規模】
40%的資料中,n<=20;
60%的資料中,m=2;
80%的資料中,n<=10^5。
100%的資料中,n<=10^15。
分析:額,本來想刷數學題的,結果被這道題撞車了,實在好久沒寫過矩陣快速冪,於是各種qiao。首先80%不難想到狀壓dp,因為m小於5嘛,然後定義轉移方程f[i]
[j],表示拿到第i個花時,後m個花的狀態是j的方案數,現在考慮哪些狀態可以轉移,不難看出j狀態可以由j>>2+1,j>>2+2^(m-1)+1(手動模擬一下吧),這兩個狀態轉移過來於是打上標記con[i]
[j],於是可以寫出乙個n*2^(m-1)*
2^(m-1)的轉移方程,f[i]
[j]=f[
i-1][k
]+f[i]
[j]。這是80分的做法,現在n太大於是考慮優化,我們觀察一下可以發現,後面的每種方案數其實就是前面的方案遞推過去的,遞推規則是不變的,且推了n次,然後手動玩了下樣例,發現最後的方案數就等於最開始處理出來的con[i]
[j]的n次方,於是考慮矩陣快速冪(很裸的)。最後也是最玄學的地方,你可以玩個樣例觀察一下,發現答案就是矩陣的對角線和,至於為什麼,可以這樣考慮,我們最後算出的結果肯定是sigma(f[
n+m][i
]),而對角線上的點的值其實就對應每種狀態i,於是考慮把它們加起來得到最優解。最後說一下,取模一定要勤快。
# include # include # include # include # include # include # include # include using namespace std;
typedef long long ll;
ll read()
while(ch>='0'&&ch<='9')
return f*i;
}const int mod=1000000007;
ll con[40][40],res[40][40],n,m,k,tmp[40][40];
bool vis[40];
inline void mul(ll s[40],ll t[40])
}int main()
if(sum<=k)
res[i][i]=1;
} kum();ll ans=0;
for(int i=0;i<(1<
狀壓dp 矩陣 洛谷 P1357 花園
簡單來說,這一題就是乙個狀壓dp用矩陣優化 但是這個矩陣也是最最最基礎的矩陣了 floyd矩陣 dp的話,和第乙個題解hi一樣的 f i s 表示第i位時的方案,s為i i m 1的狀態 然後轉移的時候我們列舉i列舉2個s if v j k f i j f i j f i 1 k mo 這裡的v j...
洛谷 1357 花園
的運算優先順序低於 貌似對矩陣理解更深刻了!2 m 5,相鄰的m個花圃可能有2 m種狀態 用0 2 m 1來表示 要求有不超過k個c形花圃,對應其二進位制形式中的0不超過k個。標記出0 2 m 1中滿足條件的狀態x,對於每個狀態x,前m個花圃會出現1次 f i,x 表示前i個花圃中,最後m個花圃的狀...
洛谷 1357 花園
的運算優先順序低於 貌似對矩陣理解更深刻了!2 m 5,相鄰的m個花圃可能有2 m種狀態 用0 2 m 1來表示 要求有不超過k個c形花圃,對應其二進位制形式中的0不超過k個。標記出0 2 m 1中滿足條件的狀態x,對於每個狀態x,前m個花圃會出現1次 f i,x 表示前i個花圃中,最後m個花圃的狀...