求放k個棋子在n*n的棋盤上,最少互相攻擊的棋子對數。
能夠攻擊僅當兩旗子在一條直線上,且中間無障礙物。
共有q個詢問
不難想到這種棋盤上放棋子的題考得是網路流
積累:按行、縱分別按其對應連通塊編號,s->行->縱->t
但明顯新一行的點互相攻擊的話,隨點數的增加,貢獻是0,1,2,3這樣遞增的。
於是我們想到給s->行,縱->t連邊時 連多條(val=0,1,2,3…,flow=1)的邊
最後 行->縱 連(val=0,flow=1)即可
好像忘了一件事,多個詢問,用費用流每次增一條路,預處理出來就行
注意預估邊條數和點個數
#include
using
namespace std;
const
int n=
6e3+
10,m=
2e5+
10,q=
1e3+
10,inf=
1e9+7;
int s,t,max_flow;
int n;
int head[n]
,nex[m]
,to[m]
,flow[m]
,val[m]
,tot=1;
void
build
(int u,
int v,
int f,
int w)
int mp[55]
[55];
int bl[2]
[55][
55];void
make_build()
else bl[0]
[i][j]
=re0,pre0=0;
}re0++
;pre0=1;
}int re1=
1,pre1=0;
for(
int i=
1;i<=n;i++
)else bl[1]
[i][j]
=re1,pre1=0;
}re1++
;pre1=1;
}//pre用來盡量壓點個數,但可能沒什麼用
s=0,t=re0+re1+
1,max_flow=t;
for(
int i=
1;i<=re0;i++
)for
(int k=
0;k)build
(s,i,
1,k)
;for
(int i=
1;i<=re1;i++
)for
(int k=
0;k)build
(i+re0,t,
1,k)
;for
(int i=
1;i<=n;i++
)for
(int j=
1;j<=n;j++)}
int dis[n]
,flw[n]
,pre[n]
;bool vis[n]
;bool
spfa()
}}return dis[t]
<
0x3f3f3f3f;}
intdoit()
}return tmp;
}int q;
int ans[
2510];
struct qus
}qu[q]
;char s[55]
;int
main()
make_build()
;for
(int i=
1;i<=all;i++
) ans[i]
=ans[i-1]
+doit()
;scanf
("%d"
,&q)
;for
(int fw,i=
1;i<=q;i++
)return0;
}
2017 山東一輪集訓 Day4 基因
設定 sqrt 個關鍵點,維護出關鍵點到每個右端點之間的答案以及pam的左指標,每次暴力向左插入元素即可,為了去重,還需要記錄一下pam上每個節點在每個關鍵點為左端點插入到時候到最左邊出現位置,總複雜度 o n sqrt program by mangoyang pragma gcc optimiz...
2018山東一輪集訓 Tree
為什麼出題人這麼毒瘤啊?乙個分塊還要帶log的題非要出成n 2 1e5。為了卡過最後兩個點我做了無數常數優化,包括但不限於 把所有線段樹改成 存差分的樹狀陣列 把樹剖求lca的極小的log優化成rmq o 1 求lca 根據測試情況手動調整siz的大小 但就是死也卡不過去,算了算了qwq 常規套路,...
2017 山東一輪集訓 Day7 逆序對
題解 滿滿的套路題。首先顯然從大到小列舉 然後每次生成的逆序對是1 i 1 的 這樣做dp是nk的 複雜度太高了 那我們轉化一下問題 變成sigma ai ai 據說是個經典問題。感覺非常奇妙 先容斥一下,也就是說 總的 至少1個條件不滿足 至少2個條件不滿足 那考慮一下如何算有x個條件不滿足 不滿...