點此看題面
大致題意:你要在\(m\)個格仔中擺放\(n\)個魔法師(每個魔法師有乙個攻擊範圍),使他們不能互相攻擊,求方案數。
要用魔法戰勝魔法!(顯然我不會魔法只會膜法,所以就被這道題吊錘了)
這是一道比較有趣的題。
題意看起來很簡單,資料範圍好像也很小,於是我就先後飛快地有了兩個想法,然後又先後飛快地hack掉了自己。。。
考慮假設我們已知要佔據\(k\)個格仔,那麼此時的方案數就相當於在\(m-k\)個格仔中插入\(n\)塊板的方案數,應該是\(c_^n\)。
所以我們就有乙個想法, 即維護要佔據的格仔數。
然後發現乙個魔法師的攻擊範圍對答案有貢獻,需要他旁邊的魔法師攻擊範圍比他小。
因此,我們可以從大到小列舉每乙個魔法師。
而乙個攻擊範圍小的魔法師無論放在哪個魔法師旁邊其實不會對佔據的格仔數造成影響,因此當我們列舉到乙個魔法師時便可以決定好之後要在他旁邊放多少個魔法師,然後只要記錄當前預留了幾個格仔,就能轉移了。
具體地,我們設\(f_\)表示放了攻擊範圍前\(i\)大的魔法師,預留了\(j\)個格仔,佔據了\(k\)個格仔的方案數。
然後就有第\(i\)個魔法師旁邊決定預留\(0/1/2\)個格仔的三種情況轉移(注意\(i\)本身要佔據乙個格仔),即:
\[f_=(j+1)\times f_+j\times f_\times 2+(j-1)\times f_
\]而初始條件為\(f_=1\),即一開始有乙個格仔,第乙個魔法師要佔據乙個格仔。
具體實現可以詳見**。
#include#define tp template#define ts template#define reg register
#define ri reg int
#define con const
#define ci con int&
#define i inline
#define w while
#define n 40
#define m 1000000
#define x 1000000007
#define c(x,y) (1ll*fac[x]*ifac[y]%x*ifac[(x)-(y)]%x)
#define inc(x,y) ((x+=(y))>=x&&(x-=x))
using namespace std;
int n,m,a[n+5],f[n+5][n+5][n*n+5],fac[m+5],ifac[m+5];
i int qp(ri x,ri y)
i bool cmp(ci x,ci y) //從大到小排序
int main()
BZOJ 4498 魔法的碰撞
魔法總是令戰鬥的局面變幻莫測。然而魔力的碰撞則更是天馬行空,甚至會出現無法控制而自取滅亡的情況。因此,魔力碰撞總是沒有辦法的辦法。設想有一條長度為l的戰線,你可以把你的魔法師們安排在戰線上的每個格仔。每乙個魔法師都有乙個攻擊範圍di,排兵時必須保證任意兩個魔法師的攻擊範圍的較大值小於等於它們之間的距...
BZOJ4498 魔法的碰撞 DP
我們先考慮全部緊湊的情況,也就是沒有多餘的空格的情況 將d id i di 先不考慮魔法師佔的空間 這裡用了乙個很巧妙的方法,多加一維,表示預留的空位。加入a會有三種情況 e表示空位 a,ae或ea,eae。對於第一種,表示a兩邊都有魔法師。對於第二種,表示a的一邊有,一邊沒有。對於第三種,表示a的...
BZOJ4498 魔法的碰撞(組合數學 dp)
傳送門 首先我們發現乙個排列,2個魔法使之間一定要填max di,di 1 1max d i,d 1 max di di 1 1個格仔而如果總共一定要填的為k kk個,貢獻就是 l kn n l k 考慮dpdp dp出每種情況的方案數 首先按d dd從大到小排序消除max maxma x我們發現乙...