這道題是我看了題解以後才做出來的,真是一道神題,但是寫題解的大神都不願解釋得太詳細,所以我想了很久才想明白。。
看了題解以後真的覺得很像數的劃分、約瑟夫問題還有國王遊戲,**出奇地簡潔,但是思維量相當地高。
主要思路:離散。
三個引理:
①在n->n-1的轉化過程中,我們刪除了乙個點後,我們可以將n-1個點視為仍是1~n-1的排列。
②在若排列pn為乙個合法抖動子串行,則交換i∈[1,n)與i+1,必能得到另乙個抖動子串行。
③抖動序列的對稱性,若存在第一段上公升的長度為n的抖動子串行,則以n+1-x代x必能得到乙個第一段下降的長度為n的抖動子串行。
設f[i][j]為長度為i的,以j開頭的,第一段下降的抖動子串行的個數,則循題意可得2*f[n+1][n+1]即為答案。
考慮轉移:
①若j的下乙個是j-1,則需要乙個長度為n-1的,以j-1開頭的上公升子串行;
再分兩種情況:
若j==n,則j-1為i-1中正數第乙個數,所以可以轉移到f[i][1];
若j我們根據狀態設定,顯然有f[i][0]=f[i][1]=0.
∴f[i][j]->f[i-1][j-i].
②若j的下乙個不是j-1,則對於任意乙個以j-1開頭的下降子串行,均可以通過交換j-1和j+1得到。
∴f[i][j]->f[i][j-1]
綜,f[i][j]=f[i-1][j-i]+f[i][j-1].
減少**量?乙個技巧:
改變狀態,令f[i][j]=f[i+1][j+1],則初始狀態變更為f[1][1]=1,i∈[1,n],j∈[1,n].
#includeusing namespace std;
#include#include#include#includeint f[2][10001];
int main()
printf("%d",(f[tmp][n]<<1)%p);
}
兩年後再來做這道題——這是什麼奇怪的做法嘛!
完全可以令f[i][j][k]表示1~i在最終的排列中被分成j段,兩邊有k個是上公升的。
那麼新加入乙個i+1,可以加在兩邊,或者新建一段,或者連線兩段——就這麼無腦!
而且吐槽一下兩年前的我,是不是看題解看懵逼了,第乙個做法感覺完全可以暴力列舉下一位然後字首和優化一下就行了嘛。。。並不需要考慮太複雜。
#include#includeusing namespace std;
const int n=4200+5;
typedef long long ll;
int f[n][n][3];
int main()
printf("%d\n",((f[n][1][0]+f[n][1][1])%p+f[n][1][2])%p);
}
SDOI2010 地精部落
求1 n的全排列數目,使得對於 i geq 3 a a 的大小關係與 a a 的大小關係不同 題目還有另外一種格式 求一種全排列,使得這個排列要麼滿足奇數項的高度比相鄰位置都大,要麼滿足偶數項的高度比相鄰位置都大.設 dp 表示用了前 i 個數字,a 1 j 且 a 1 a 2 時的方案數 有乙個神...
SDOI2010 地精部落
這道題是一道 dp 題,思維難度比較大。題意 先定義波形陣列 滿足當 i 全為奇數或偶數時,a i a i 1 且 a i a i 1 求 n 的全排列中有多少個符合波形陣列。我們記錄狀態為 f i j 0 1 i 為剩下 i 個數,j 表示有 j 1 個數小於剛剛選擇的數,當第 3 個下標為 0 ...
SDOI2010 地精部落
sdoi2010 地精部落 僅含一行,兩個正整數 n,p。僅含一行,乙個非負整數,表示你所求的答案對p取餘 之後的結果。4 7對於 20 的資料,滿足 n 10 對於 40 的資料,滿足 n 18 對於 70 的資料,滿足 n 550 對於 100 的資料,滿足 3 n 4200,p 109 我覺得...