首先,这东西稍微有一点 constructive \text{constructive} constructive,所以我未必能想到;其次,按照我愚蠢的方法, 100 % 100\% 100% 的想不到。
原本我以为,可以最大权闭合子图乱搞;但是这里的权值需要设置为负数(四个点之中有一个点不保留,就可以获得大量权值;这是一个负数的割),计划泡汤。我又联想到了黑白染色。
我一想:“ x i , y i x_i,y_i xi,yi 均为偶数,不就是所有的黑点嘛!” 于是开始了轰轰烈烈的尝试,然后以失败告终。
直到看到题解,我才发现:原来 x i , y i x_i,y_i xi,yi 均为偶数,并不是 2 ∣ ( x i + y i ) 2\mid(x_i+y_i) 2∣(xi+yi) 啊,长见识了!
回到正题上。首先这是线性规划;于是考虑网络流。虽然最大权闭合子图是错误的,但是我们有别的方法让它正确。记 f ( x , y ) f(x,y) f(x,y) 为,是否 ( x , y ) (x,y) (x,y) 存在点,且左侧和右侧至少有一个点。那么存在平行四边形,等价于 f ( x , y ) f(x,y) f(x,y) 且 f ( x , y + 1 ) ∨ f ( x , y − 1 ) f(x,y{\rm+}1)\vee f(x,y{\rm-}1) f(x,y+1)∨f(x,y−1),其中 2 ∣ x , 2 ∣ y 2\mid x,\;2\mid y 2∣x,2∣y 。
那么,只需考虑删点对于 f ( x , y ) ( 2 ∣ x ) f(x,y)\;(2\mid x) f(x,y)(2∣x) 的影响。可以发现,其左右的两个点都可以为它 “供能”,想要它为 false \texttt{false} false,要么左右两侧都不选,要么自己不选。这是简单的网络流模型:左右两侧的点都向新点 t t t 连 + ∞ +\infty +∞ 容量的边(若有一个是 S S S 部,则 t t t 是 S S S 部),然后 t t t 向当前点连边,容量是 w x w_x wx,即自己不选时(此边被割掉)无论左右如何自己都可以是 T T T 部。
由于 2 ∣ y 2\mid y 2∣y 和 2 ∤ y 2\nmid y 2∤y 互不影响,两边分别如此建图。问题则变为 f ( x , y ) f(x,y) f(x,y) 和 f ( x , y + 1 ) f(x,{y{\rm+}1}) f(x,y+1) 不能同时为 true \texttt{true} true 。现在总算可以黑白染色了:将 2 ∣ y 2\mid y 2∣y 的 S , T S,T S,T 状态翻转,问题则变为,某种二者取值不同的情况是被禁止的。连 + ∞ +\infty +∞ 容量的边,表示不可接受的代价,就行了。
重新审视网络流图,你会发现:实际上我们建出了这样的一个图: ( 1 , 1 ) → ( 0 , 1 ) → ( 0 , 0 ) → ( 1 , 0 ) (1,1)\to(0,1)\to(0,0)\to(1,0) (1,1)→(0,1)→(0,0)→(1,0),其中 0 , 1 0,1 0,1 代表奇偶性,并且每个点拆成了入度和出度。那么这就很 constructive \text{constructive} constructive 了:它实际上揭示了一种将平行四边形拆解成路径的方式,而且这个路径也总是对应平行四边形。
题解多数都是上面的这种 constructive \text{constructive} constructive 讲法,包括官方题解。这谁能想得到嘛
可是这跟我连奇偶都分不清有什么关系呢。时间复杂度
O
(
n
3
)
\mathcal O(n^3)
O(n3),即
O
(
V
2
E
)
\mathcal O(V^2E)
O(V2E) 的网络流。
#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cctype>
#include <map>
using namespace std;
# define rep(i,a,b) for(int i=(a); i<=(b); ++i)
# define drep(i,a,b) for(int i=(a); i>=(b); --i)
typedef long long llong;
inline int readint(){
int a = 0, c = getchar(), f = 1;
for(; !isdigit(c); c=getchar())
if(c == '-') f = -f;
for(; isdigit(c); c=getchar())
a = (a<<3)+(a<<1)+(c^48);
return a*f;
}
const int MAXN = 2005, INF = 0x3fffffff;
struct Edge{
int to, nxt, val;
Edge(int _t,int _n,int _v)
:to(_t),nxt(_n),val(_v){}
Edge() = default;
};
Edge e[MAXN<<2];
int head[MAXN], cntEdge;
void addEdge(int a,int b,int v){
e[cntEdge] = Edge(b,head[a],v);
head[a] = cntEdge ++;
e[cntEdge] = Edge(a,head[b],0);
head[b] = cntEdge ++;
}
int dis[MAXN];
bool bfs(const int source,const int sink){
static int q[MAXN]; // queue
int *fro = q, *bac = q+1;
memset(dis+1,-1,sink<<2);
*bac = source, dis[*bac] = 0;
for(int x; fro!=bac; ){
++ fro, x = *fro;
for(int i=head[x]; ~i; i=e[i].nxt)
if(e[i].val && !(~dis[e[i].to])){
dis[e[i].to] = dis[x]+1;
++ bac, *bac = e[i].to;
}
}
return dis[sink] != -1;
}
int cur[MAXN];
int dfs(int x,int inFlow,const int sink){
int sum = 0; if(x == sink) return inFlow;
for(int &i=cur[x]; ~i; i=e[i].nxt)
if(e[i].val && dis[e[i].to] == dis[x]+1){
int d = dfs(e[i].to,min(inFlow-sum,e[i].val),sink);
e[i].val -= d, e[i^1].val += d, sum += d;
if(sum == inFlow) break; // no more flow
}
if(sum != inFlow) dis[x] = -1;
return sum;
}
llong dinic(const int source,const int sink){
long long res = 0;
while(bfs(source,sink)){
memcpy(cur+1,head+1,sink<<2);
for(int &i=cur[source]; ~i; i=e[i].nxt)
if(e[i].val) res += dfs(e[i].to,e[i].val,sink);
}
return res;
}
int x[MAXN], y[MAXN];
map<pair<int,int>,int> mp;
int main(){
int n = readint(); llong ans = 0;
const int source = (n<<1)|1, sink = source+1;
memset(head+1,-1,sink<<2);
rep(i,1,n){
x[i] = readint(), y[i] = readint();
mp[make_pair(x[i],y[i])] = i;
int w = readint(); ans += w;
addEdge(i+n,i,w); // if cut
}
rep(i,1,n)
if((x[i]^y[i]^1)&1){
rep(d,-1,1) if(d && mp.count(make_pair(x[i]+d,y[i])))
addEdge(i,mp[make_pair(x[i]+d,y[i])]+n,INF);
if(x[i]&y[i]&1) addEdge(source,i+n,INF);
}
else if(!(x[i]&1) && (y[i]&1)){
rep(d,-1,1) if(d && mp.count(make_pair(x[i],y[i]+d)))
addEdge(i,mp[make_pair(x[i],y[i]+d)]+n,INF);
}
else if((x[i]&1) && !(y[i]&1)) addEdge(i,sink,INF);
printf("%lld\n",ans-dinic(source,sink));
return 0;
}
如果说思维就是大脑皮层的电信号,那么定义电阻率的比值 ρ O n e I n D a r k ρ D D ( X Y X ) = sb ( t ) \frac{\rho_{\sf OneInDark}}{\rho_{\sf DD(XYX)}}=\operatorname{sb}(t) ρDD(XYX)ρOneInDark=sb(t) 为 O n e I n D a r k \sf OneInDark OneInDark 的废物指数(随时间变化的函数)。在 2005 2005 2005 年,青年数学家戴伟鸥和严逸袅先后分别完成了对于 sb ( t ) \operatorname{sb}(t) sb(t) 任意阶导数单增、 sb ( t ) ≫ ω 100 t ( ω ≫ 1 0 1 0 10 ) \operatorname{sb}(t)\gg\omega^{100t}\;(\omega\gg 10^{10^{10}}) sb(t)≫ω100t(ω≫101010) 的证明。