排列計數的乙個經典做法就是按照某種順序將元素不斷往序列中插入,不難發現本題的第一問為了方便知道每個位置前面有多少個大於當前位置,我們可以考慮按高度從大到小地將一座座山不斷插入序列。假設當前沒有高度相同的山,當前考慮插入第 \(i\) 座山,\(_\) 是當前山的關鍵字,那麼我們能插入的位置就有 \(\min\_\}\) 個,根據乘法原理乘起來即可。但現在有相同高度的山就比較難處理了,不難發現難處理的地方在於不同的插入序列可能對應著一種排列方式,那麼我們經典的乙個想法就是欽定一種插入順序使得他能對應生成出所有的排列方式。於是我們可以發現,每次讓關鍵字最小的山先插入是能覆蓋到所有情況的,因為關鍵字小的山貢獻出來的新位置後面關鍵字大的山也能插,但反之就不行了。於是我們按照高度為第一關鍵字從大到小,按關鍵字為第二關鍵字從小到大排序,每個位置能插入的位置有 \(\min\_ + cnt\}\) 個,\(cnt\) 為他之前有多少個高度相同的山,根據乘法原理將這些數簡單相乘即可。
再來考慮第二問,可以發現不同高度的山是不會對記重有影響的,因此我們只需要考慮每個高度的方案再根據乘法原理簡單相乘即可。接下來我們可以發現實際上高度相同的山都是一樣的,那麼我們的問題可以轉化為有 \(n\) 個無標號的求每個求能放到 \(1 \sim \min\_\}\) 個盒子當中,求方案數。因為球是相同的,因此我們乙個方案會記重當且僅當某些球會交換位置,於是為了不讓球能交換位置,我們欽定每次放球都必須放在上一次放球的那個盒子和以後的盒子中,這樣就不會記重了。於是根據這個方法我們有了乙個 \(dp\),令 \(dp_\) 表示前 \(i\) 個球放到前 \(j\) 個盒子的方案,那麼有轉移 \(dp_ = \sum\limits_ ^ j dp_\),發現這是乙個字首和的形式,於是我們壓掉第一維,可以得到轉移 \(dp_ = dp_ + dp_i\),注意初始化 \(i = 1\) 的情況,因為直接初始化 \(i = 0\) 會出現 \(dp_0 = 0\) 到後面會計算非法答案。
#includeusing namespace std;
#define n 1000 + 5
#define mod 2011
#define rep(i, l, r) for(int i = l; i <= r; ++i)
struct nodea[n];
int n, ans, s[n], fac[n], inv[n], dp[n];
int read()
while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
return x * f;
}int inc(int a, int b)
int mul(int a, int b)
int qpow(int a, int b)
return ans;
}bool cmp(node a, node b)
int main()
printf("%d ", ans), ans = 1;
rep(i, 1, n)
rep(k, 1, min(i, a[j - 1].val)) tmp = inc(tmp, dp[k]);
ans = mul(ans, tmp);
i = j - 1;
}printf("%d", ans);
return 0;
}
JLOI2013 地形生成 組合計數
n 元素各有乙個高度 h 和關鍵數字 b 求有多少個下標序列和高度序列,滿足對任意 i j i 且 h j h i 的 j 個數小於 b i 高度序列 總時間複雜度為 o n 2 處理組合計數問題的技巧 插入數字或者保留位置 排列 rightarrow 組合 強制放置有序即可 includeusin...
bzoj 3193 JLOI2013 地形生成
難忘多少個日子之前,我對著這道題死磕了將近1 4 4 3 h的情景 差不多有一整個學校日 上午 下午 晚自習 都是淚啊 include include include include include using namespace std define maxn 1005 const int inf...
bzoj3193 JLOI2013 地形生成
最近ik正在做關於地形建模的工作。其中乙個工作階段就是把一些山排列成一行。每座山都有各不相同的標號和高度。為了遵從一些設計上的要求,每座山都設定了乙個關鍵數字,要求對於每座山,比它高且排列在它前面的其它山的數目必須少於它的關鍵數字。顯然滿足要求的排列會有很多個。對於每乙個可能的排列,ik生成乙個對應...