10.29 模拟赛

10.29 模拟赛

T1 旅行

考虑建立虚点表示上边界和下边界

要求的实际上是上边界到下边界的瓶颈路

于是可以建最小生成树

用kruskal是 mlog 的

所以用$n^2 + m$的prim算法

但是可以不用真正建立出最小生成树,只需要类似最小生成树地跑瓶颈路就可以了

每次更新的时候拿距离最小值来更新。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
#define MAXN 7006
int n , m , k;
int x[MAXN] , y[MAXN];
double dis[MAXN];
bool vis[MAXN];
double getdis( int a , int b ) {
return sqrt( 1.0 * ( x[a] - x[b] ) * ( x[a] - x[b] ) + 1.0 * ( y[a] - y[b] ) * ( y[a] - y[b] ) );
}
double ans = 0.0;
int main() {
cin >> n >> m >> k;
for( int i = 1 ; i <= k ; ++ i ) scanf("%d%d",&x[i],&y[i]) , dis[i] = ( 1.0 * m - y[i] );
dis[k + 1] = m;
for( int t = 1 ; t <= n + 1 ; ++ t ) {
int nd = k + 1;
for( int i = 1 ; i <= k ; ++ i ) if( !vis[i] && dis[i] < dis[nd] ) nd = i;
ans = max( ans , dis[nd] );
if( nd == k + 1 ) return printf("%.7lf",ans / 2.0) , 0;
for( int j = 1 ; j <= k ; ++ j ) if( !vis[j] )
dis[j] = min( dis[j] , getdis( nd , j ) );
vis[nd] = 1;
dis[k + 1] = min( dis[k + 1] , 1.0 * y[nd] );
}
printf("%.7lf",ans / 2.0);
}

T2 寻宝

考虑一个点只会往三个方向走:

_Z___`FHJX_6_Q25O_W_D_H.png

其中另一个方向是没有价值的。

然后可以贪心走代价最小的,可以被证明是正确的。

我用了五个set来维护,所以T了。。。不建议看这个代码。。(

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// /kel
#pragma GCC optimize(3)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<set>
#include<unordered_set>
using namespace std;
#define MAXN 300006
#define pii pair<int,int>
#define mp node
#define fi a
#define se b
struct node {
int a , b;
node( int a = 0 , int b = 0 ) : a ( a ) , b ( b ) {}
bool operator < ( const node x ) const {
return a == x.a ? b < x.b : a < x.a;
}
};
//typedef tree<node, null_type, less<node>, rb_tree_tag, tree_order_statistics_node_update> rbtree;
set<node> s1 , s3 , s2 , s2x , s2y;
// s1 sorted by y , s2 sorted by x + y , s3 sorted by x
int n;
void read( int& x ) {
x = 0; char ch = ' ';
while( ch > '9' || ch < '0' ) ch = getchar();
while( ch >= '0' && ch <= '9' ) { x *= 10 , x += ch - '0' , ch = getchar(); }
}
int X[MAXN],Y[MAXN];
int curx , cury , res = 0;
int main() {
cin >> n;
for( int i = 1 ; i <= n ; ++ i ) {
read(X[i]) , read(Y[i]);
s2.insert( mp( X[i] + Y[i] , i ) );
s2x.insert( mp( X[i] , i ) );
s2y.insert( mp( Y[i] , i ) );
}
curx = cury = 1;
int tp;
for( register int i = 1 ; i <= n ; ++ i ) {
node t = {0x7f7f7f7f,0x7f7f7f7f}; int curr = 0x7f7f7f7f;
if( !s1.empty() ) if( curr > ( s1.begin() -> fi - cury ) ) t = *s1.begin() , curr = ( s1.begin() -> fi - cury ) , tp = 1;
if( !s2.empty() ) if( curr > ( s2.begin() -> fi - curx - cury ) ) t = *s2.begin() , curr = ( ( s2.begin() -> fi - curx - cury ) ) , tp = 2;
if( !s3.empty() ) if( curr > ( s3.begin() -> fi - curx ) ) t = *s3.begin() , curr = ( s3.begin() -> fi - curx ) , tp = 3;
// printf("%d %d ",s3.begin()->fi,s3.begin()->se); puts("");
int id = t.se;
printf("%d ",id);// puts("");
// res = max( res , max( P[id].x - curx , 0 ) + max( P[id].y - cury , 0 ) );
if( tp == 1 ) {
auto to3 = s2y.upper_bound( mp( Y[id] - 1 , 0x7f7f7f7f ) ) , cc = to3;
if( to3 == s2y.begin() ) goto fuk;
-- to3;
for( ; ; ) {
int x = X[to3->se];
s2.erase( mp( x + Y[to3->se] , to3 -> se ) );
s2x.erase( mp( x , to3->se ) );
s3.insert( mp( x , to3->se ) );
if( to3 == s2y.begin() ) break;
-- to3;
}
for( auto it = s2y.begin() ; it != cc ; ++ it ) s2y.erase( s2y.begin() );
// s2y.erase( s2y.begin() , cc );
fuk: s1.erase( mp( Y[id] , id ) );
cury = Y[id];
} else if( tp == 2 ) {
auto to1 = s2x.upper_bound( mp( X[id] - 1 , 0x3f3f3f3f ) ) , cc = to1;
if( to1 == s2x.begin() ) goto skip;
-- to1;
for( ; ; ) {
int y = Y[to1->se];
s2.erase( mp( X[to1->se] + y , to1 -> se ) );
s2y.erase( mp( y , to1->se ) );
s1.insert( mp( y , to1->se ) );
if( to1 == s2x.begin() ) break;
-- to1;
}
for( auto it = s2x.begin() ; it != cc ; ++ it ) s2x.erase( s2x.begin() );
skip: auto to3 = s2y.upper_bound( mp( Y[id] - 1 , 0x7f7f7f7f ) ); cc = to3;
if( to3 == s2y.begin() ) goto jump;
-- to3;
for( ; ; ) {
int x = X[to3->se];
s2.erase( mp( x + Y[to3->se] , to3 -> se ) );
s2x.erase( mp( x , to3->se ) );
s3.insert( mp( x , to3->se ) );
if( to3 == s2y.begin() ) break;
-- to3;
}
for( auto it = s2y.begin() ; it != cc ; ++ it ) s2y.erase( s2y.begin() );
jump: s2.erase( mp( X[id] + Y[id] , id ) );
s2x.erase( mp( X[id] , id ) ) , s2y.erase( mp( Y[id] , id ) );
curx = X[id] , cury = Y[id];
} else {
auto to1 = s2x.upper_bound( mp( X[id] - 1 , 0x7f7f7f7f ) ) , cc = to1;
if( to1 == s2x.begin() ) goto qq;
-- to1;
for( ; ; ) {
int y = Y[to1->se];
s2.erase( mp( X[to1->se] + y , to1 -> se ) );
s2y.erase( mp( y , to1->se ) );
s1.insert( mp( y , to1->se ) );
if( to1 == s2x.begin() ) break;
-- to1;
}
for( auto it = s2x.begin() ; it != cc ; ++ it ) s2x.erase( s2x.begin() );
qq: s3.erase( mp( X[id] , id ) );
curx = X[id];
}
}
// cout << res << endl;
}

T3 鞋子

考虑先求出一个鞋子的最大匹配。然后如果整个图不是全部鞋子都被匹配的,显然可以给当前的鞋子都做到最大匹配。因为考虑我们如果有一个位置的鞋子是没用的,我们可以用它转动来让整个图变成期望的模样。(它可以通过一些中间步骤转动任何一个位置的鞋子)

然后考虑如果是一个完美的匹配,这个时候答案要么是完美匹配要么是完美匹配-1,所以就random一下输出所以我们可以考虑什么时候可以转出一个完美匹配。结论是:对 U , R , D , L 标号为 0 , 1 , 2 , 3 , 那么完美匹配的情况的整个图的和模四和初始状态的整个图模四应当相同。证明可以看题解。。(我不会wsl大概就是先说明完美匹配权值对四取模相同,在说明任意权值对四取模是互相可达的。

对于当前的完美匹配,如果有一对横着的鞋子对答案无改变,因为转出来一定得是 0 , 0 或者 4 , 4 ,竖着的一对鞋子对答案改变了 2 ,因为一定是 1 , 1 或者 3 , 3

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<queue>
using namespace std;
#define MAXN 1006
int ed = 0;
class maxFlow {
public:
typedef long long ll;
std::queue<int> q;
std::vector<int> head, cur, nxt, to, dep;
std::vector<ll> cap;

maxFlow(int _n = 0) { init(_n); }
void init(int _n) {
head.clear();
head.resize(_n + 1, 0);
nxt.resize(2);
to.resize(2);
cap.resize(2);
}
void init() { init(head.size() - 1); }
int add(int u, int v, ll w) {
nxt.push_back(head[u]);
int x = ( head[u] = to.size() );
to.push_back(v);
cap.push_back(w);
return x;
}
int Add(int u, int v, ll w) {
// printf("%d %d %d\n",u,v,w);
add(u, v, w);
return add(v, u, 0);
}
void del(int x) { cap[x << 1] = cap[x << 1 | 1] = 0; }
bool bfs(int s, int t, int delta) {
dep.clear();
dep.resize(head.size(), -1);
dep[s] = 0;
q.push(s);
while (!q.empty()) {
int u = q.front();
q.pop();
for (int i = head[u]; i; i = nxt[i]) {
int v = to[i];
ll w = cap[i];
if (w >= delta && dep[v] == -1) {
dep[v] = dep[u] + 1;
q.push(v);
}
}
}
return ~dep[t];
}
ll dfs(int u, ll flow, int t, int delta) {
if (dep[u] == dep[t])
return u == t ? flow : 0;
ll out = 0;
for (int& i = cur[u]; i; i = nxt[i]) {
int v = to[i];
ll w = cap[i];
if (w >= delta && dep[v] == dep[u] + 1) {
ll f = dfs(v, std::min(w, flow - out), t, delta);
cap[i] -= f;
cap[i ^ 1] += f;
out += f;
if (out == flow)
return out;
}
}
return out;
}
ll maxflow(int s, int t) {
ll out = 0;
ll maxcap = *max_element(cap.begin(), cap.end());
for (ll delta = 1ll << int(log2(maxcap) + 1e-12); delta; delta >>= 1) {
while (bfs(s, t, delta)) {
cur = head;
out += dfs(s, 0x7fffffffffffffffll, t, delta);
}
}
return out;
}
ll getflow(int x) const { return cap[x << 1 | 1]; }
} G ;
const int dirx[5] = { 0,0,0,1,-1 };
const int diry[5] = { 0,1,-1,0,0 };
int toint[300];
int n , m;
int lr[MAXN][MAXN] , dir[MAXN][MAXN];
char ch[MAXN][MAXN] , chh[MAXN][MAXN];
vector<int> E[MAXN][MAXN];
int main() {
toint['U'] = 0 , toint['R'] = 1 , toint['D'] = 2 , toint['L'] = 3;
cin >> n >> m;
for( int i = 1 ; i <= n ; ++ i )
scanf("%s",ch[i] + 1);
G.init( n * m * 2 );
int s = n * m * 2 - 1 , t = n * m * 2 - 2;

for( int i = 1 ; i <= n ; ++ i )
for( int j = 1 ; j <= m ; ++ j )
if( ch[i][j] == 'L' ) {
int poi = ( i - 1 ) * m + j;
G.Add( s , poi , 1 );
for( int d = 1 ; d <= 4 ; ++ d ) {
int x = i + dirx[d] , y = j + diry[d];
if( x <= n && y <= m && x && y && ch[x][y] == 'R' )
E[i][j].push_back( G.Add( poi , ( x - 1 ) * m + y , 1 ) );
}
} else {
int poi = ( i - 1 ) * m + j;
G.Add( poi , t , 1 );
}
int res = G.maxflow( s , t );
for( int i = 1 ; i <= n ; ++ i ) {
scanf("%s",chh[i] + 1);
}
if( ( n * m ) & 1 || res != n * m / 2 ) {
printf("%d\n",res);
} else {
int resl = 0 , resr = 0;
for( int i = 1 ; i <= n ; ++ i )
for( int j = 1 ; j <= m ; ++ j ) {
resr += toint[chh[i][j]];
}

for( int i = 1 ; i <= n ; ++ i )
for( int j = 1 ; j <= m ; ++ j ) if( ch[i][j] == 'L' ) {
for( int k = 0 ; k < E[i][j].size() ; ++ k ) if( G.cap[E[i][j][k]] ) {
int to = G.to[E[i][j][k] ^ 1];
for( int d = 1 ; d <= 4 ; ++ d ) {
int x = i + dirx[d] , y = j + diry[d];
if( to == ( x - 1 ) * m + y )
if( d == 3 || d == 4 ) resl += 2;
}
}
}
if( ( resl % 4 ) == ( resr % 4 ) ) printf("%d\n",res);
else printf("%d\n",res-1);
}
}
文章作者: yijan
文章链接: https://yijan.co/1029monisai/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Yijan's Blog