題意:給定乙個深度為k的滿二叉樹,將他的所有節點向這個點的所有祖宗連邊,求新生成的這樣一棵樹中經過乙個點最多的路徑數目
怎麼搞?
顯然是個遞推嘛...
記狀態f[i][j]代表二叉樹的深度為i,從中選出j條互不相交的路徑的方案數(即這些路徑不會經過同乙個點超過一次)
然後呢?
我們會發現,由i變成i+1時,超級樹的變化就相當於將兩棵深度為i的超級樹連到乙個根上,然後將所有點與根連邊即可
據此,我們設計轉移:
記狀態f[i][l]表示深度為i+1的超級樹的左子樹中選出l條不相交的路徑,f[i][r]表示深度為i+1的右子樹中選出r條不相交的路徑的方案數
則我們可以分類轉移出f[i+1]:
①:根節點不參與轉移:
②:根節點乙個點作為一條新的路徑:
③:根節點與左右子樹中某一條邊連線(由於根節點與所有節點有連邊,所以根節點可以與所有路徑相連)
④:根節點連線了左右子樹中各一條邊(即左右子樹通過根節點連出了一條路徑)
⑤:根節點連線了左子樹或右子樹中兩條邊(即左子樹中兩條邊通過根節點相連或右子樹中兩條邊通過根節點相連)
這樣轉移就完成了,答案即為f[k][1](即深度為k的超級樹,選出一條不經過重複點的方案數)
當然,有可能會發現乙個問題:這樣轉移的第二維大小太大了,可能達到2^k,這樣顯然是不合理的
但是我們會發現,所有的轉移只設計l+r,l+r-1,l+r+1三者之間的關係,所以如果答案是f[k][1],那麼最初需要用來轉移的第二維不會超過k!
這樣我們就減小了第二維的大小
這樣問題也就解決了
時間複雜度o(k^3),k<=300時常數不小,需要卡卡常(直接一堆取模是行不通的了!)
#include #include #include #include #include #include #include #include #define ll long long
using namespace std;
ll f[305][305];
ll k,mode;
int main()
f[i][l+r+1]+=temp;
if(f[i][l+r+1]>=mode)
f[i][l+r]+=2*temp*(l+r)%mode;
if(f[i][l+r]>=mode)
if(l+r>=1)
f[i][l+r-1]+=2*temp*(l*(l-1)/2+r*(r-1)/2)%mode;
if(f[i][l+r-1]>=mode)}}
} }printf("%i64d\n",f[k][1]%mode);
return 0;
}
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張,他們等了很久也沒有等來失主,於是決定把錢平分。但錢可能無法平分。他們先把能夠平分的錢盡量先平分了,使得剩下不能平分的錢盡量少。這些不能平分的錢怎麼辦呢他?他們決定拿去賭場裡面賭一把。他們運氣太好了,那些不能平分的錢變成了雙倍,於是他們就把那個錢分了...