算是有所进步但还是稍有遗憾,差一题就能进 division championships.
更新:所有 7 题队都以 wildcard 的身份晋级NADC 了,而且如果本学校只有 wildcard 队的话,会被分到最弱的 central division,然后我们又莫名其妙的拿了个第 6,晋级NAC 了:joy:
比赛过程 #
两个队友一个简称 T,一个简称 J。
开场我从前往后读,A 比较长就直接跳过了,读了 B 感觉有点想法但又不是很确定就接着读,C 很明显是个找最大环,一开始还觉得比较麻烦,但想想不是环就是链所以直接 dfs 就行了。同时队友 J 读到 E 发现就是个矩阵乘法于是开始写,我又跟榜做了 G。之后不久队友 J 的 E 也过了。另一个队友 T 读了 H 是贪心但不会写,我此时在写 B 的暴力(但其实稍微想想暴力肯定超时但不知道为啥还是写完了)。B 暴力写完才发现会超时,此时 H 还没做出来,我看了一眼也没想法,就扔给队友 J 了。然后发现 B 好像可以 dp,然后就一边想一边写,虽然有点恶心但挺直接的,最后一遍过。写 B 的过程中队友 J 过了 H,算是签完到了。此时才一个半小时,感觉非常好,比去年顺利多了。
然后我在做 K,感觉是 dp,有点思路但不会写,队友 J 在做 J,过了样例但是 WA,队友 T 直接开 I 了(其实是最难的题 orz)。于是三个人都卡题了,不知不觉过了一个半小时我终于放弃了,此时 J 题过了一大堆,于是我就跟队友 J 换了一下题,由于队友 J 用的 python 而我又懒的看所以就准备重写,然后没想到是个超级恶心模拟题,而且写了一堆 bug,离结束还有半小时和队友 J 几乎同时过了 J 和 K。然后仔细一看 A 发现很简单但输出格式很恶心,最后虽然勉强写完但没时间 debug,以 7 题收场。
反思 #
卡题太久没有及时放弃,哪怕去读读别的题。题没有都读一遍,队友 J 其实读了 A 但感觉很麻烦,但我感觉比 J 好做多了(可能我 J 写的太烂了)。L 到最后也没人读,其实也不难,就是个二分图匹配的板子 题。所以说也不能一味的跟榜,毕竟每个人的知识点覆盖不一样。但 K 卡半天没做出来也不应该。
题解 #
数据很小,找 lca 直接暴力网上跳也可以。输出格式比较恶心,要多看几遍,注意不要把11th, 12th, 13th
输出成 11st, 12nd, 13rd
。
# include < bits/stdc++.h >
# define all ( x ) ( x ) . begin () , ( x ) . end ()
# define sz ( x ) int ( x . size ())
using namespace std ;
using ll = long long ;
using pii = pair < int , int > ;
template < typename ... T > void rd ( T & ... args ) {(( cin >> args ) , ... ) ; }
template < typename ... T > void wr ( T ... args ) {(( cout << args << " " ) , ... ) ; cout << '\n' ; }
int main () {
ios :: sync_with_stdio ( false ) ;
cin . tie ( nullptr ) ;
int n , T ;
cin >> n >> T ;
vector < vector < string >> a ( n ) ;
vector < string > name ( n ) ;
unordered_map < string , int> id ;
for ( int i = 0 ; i < n ; i ++ ) {
cin >> name [i] ;
id . try_emplace ( name [i] , id . size ()) ;
int x ;
cin >> x ;
a [i] . resize (x) ;
for ( auto& s : a [i]) {
cin >> s ;
id . try_emplace (s , id . size ()) ;
}
}
vector < vector <int >> g ( id . size ()) ;
vector <int> ind ( id . size ()) ;
for ( int i = 0 ; i < n ; i ++ ) {
int u = id [ name [i]] ;
for ( auto& s : a [i]) {
g [u] . push_back ( id [s]) ;
ind [ id [s]] ++;
}
}
vector <int> pa ( id . size ()) ;
vector <int> dep ( id . size ()) ;
auto dfs =[ & ] ( auto & dfs , int u , int p ) -> void {
pa [ u ] = p ;
for ( auto v : g [ u ]) {
if (v == p) continue ;
dep [v] = dep [u] + 1 ;
dfs (dfs , v , u) ;
}
} ;
auto lca =[ & ] ( int x , int y ) {
while ( x != y ) {
if ( dep [x] < dep [y]) swap (x , y) ;
x = pa [x] ;
}
return x ;
} ;
for ( int i = 0 ; i < id . size () ; i ++ ) {
if ( ind [i] == 0 ) {
dfs (dfs , i , i) ;
break ;
}
}
auto ordinal =[] ( int x ) {
auto s = to_string ( x ) ;
if ( x >= 11 && x <= 13 ) return s + " th " ;
if ( x % 10 == 1 ) return s + " st " ;
if ( x % 10 == 2 ) return s + " nd " ;
if ( x % 10 == 3 ) return s + " rd " ;
return s + " th " ;
} ;
while ( T -- ) {
string s , t ;
cin >> s >> t ;
int l = lca ( id [s] , id [t]) ;
int m = dep [ id [s]] - dep [l] ;
int n = dep [ id [t]] - dep [l] ;
int swaped = 0 ;
if (m > n) {
swap (m , n) ;
swaped = 1 ;
swap (s , t) ;
}
if (m == 0 ) {
swap (s , t) ;
if (n == 1 ) {
cout << s << " is the child of " << t << '\n' ;
} else {
n -= 2 ;
cout << s << " is the " ;
for ( int i = 0 ; i < n ; i ++ ) cout << " great " ;
cout << " grandchild of " << t << '\n' ;
}
} else if (m == n && m > 0 ) {
if (swaped) swap (s , t) ;
if (n == 1 ) cout << s << " and " << t << " are siblings \n" ;
else {
n --;
cout << s << " and " << t << " are " << ordinal (n) << " cousins \n" ;
}
} else if (n > m && m > 0 ) {
if (swaped) swap (s , t) ;
if (n - m == 1 )
cout << s << " and " << t << " are " << ordinal (m - 1 ) << " cousins, 1 time removed \n" ;
else
cout << s << " and " << t << " are " << ordinal (m - 1 ) << " cousins, " << n - m << " times removed \n" ;
}
}
return 0 ;
}
dp[x][y][i][used][d]
代表是否存在以坐标 ( x , y ) (x, y) ( x , y ) 的字符结尾,覆盖目标字符串的前i
个字符,转向used
次,结束时的方向是d
的走法。注意长度为i i i 的字符串最多转i − 1 i-1 i − 1 次,虽然第一个字符是没有方向的,但为了转移方便就变成了所有方向,所以枚举转向次数的话要限制一下,不然会出现长度为 2 转两次的走法。
# include < bits/stdc++.h >
# define all ( x ) ( x ) . begin () , ( x ) . end ()
# define sz ( x ) int ( x . size ())
using namespace std ;
using ll = long long ;
using pii = pair < int , int > ;
template < typename ... T > void rd ( T & ... args ) {(( cin >> args ) , ... ) ; }
template < typename ... T > void wr ( T ... args ) {(( cout << args << " " ) , ... ) ; cout << '\n' ; }
int dp [ 10 ][ 10 ][ 105 ][ 105 ][ 8 ] ;
int main () {
ios :: sync_with_stdio ( false ) ;
cin . tie ( nullptr ) ;
int n , m ;
cin >> n >> m ;
vector a ( n , vector < char >( m )) ;
for ( int i = 0 ; i < n ; i ++ ) {
for ( int j = 0 ; j < m ; j ++ ) {
cin >> a [i][j] ;
}
}
int limit ;
string s ;
cin >> limit >> s ;
limit = min ( limit , int ( s . size ())) ;
const vector < pair <int , int >> dirs {{ 1 , 0 } , { - 1 , 0 } , { 0 , 1 } , { 0 , - 1 } , { 1 , 1 } , { 1 , - 1 } , { - 1 , 1 } , { - 1 , - 1 }} ;
for ( int i = 0 ; i < n ; i ++ ) {
for ( int j = 0 ; j < m ; j ++ ) {
if ( a [i][j] == s [ 0 ]) {
for ( int d = 0 ; d < 8 ; d ++ )
dp [i][j][ 0 ][ 0 ][d] = 1 ;
}
}
}
for ( int i = 1 ; i < s . size () ; i ++ ) {
for ( int x = 0 ; x < n ; x ++ ) {
for ( int y = 0 ; y < m ; y ++ ) {
if ( a [x][y] != s [i]) continue ;
for ( int used = 0 ; used <= min (limit , i - 1 ) ; used ++ ) {
for ( int d = 0 ; d < 8 ; d ++ ) {
for ( int pd = 0 ; pd < 8 ; pd ++ ) {
auto [dx , dy] = dirs [d] ;
unsigned nx = x + dx , ny = y + dy ;
int pused = used - (d != pd) ;
// if (i==1) pused=0;
if (nx < n && ny < m && pused >= 0 && dp [nx][ny][i - 1 ][pused][pd]) {
dp [x][y][i][used][d] = 1 ;
}
}
}
}
}
}
}
for ( int i = 0 ; i < n ; i ++ ) {
for ( int j = 0 ; j < m ; j ++ ) {
for ( int d = 0 ; d < 8 ; d ++ )
if ( dp [i][j][ s . size () - 1 ][limit][d])
return cout << " Yes " , 0 ;
}
}
cout << " No " ;
return 0 ;
}
由于每个物品最多只有一个人要,所以每个点的出度最多为 1,所以每个连通分量要么是环要么是链。直接 dfs 即可。
# include < bits/stdc++.h >
# define all ( x ) ( x ) . begin () , ( x ) . end ()
# define sz ( x ) int ( x . size ())
using namespace std ;
using ll = long long ;
using pii = pair < int , int > ;
template < typename ... T > void rd ( T & ... args ) {(( cin >> args ) , ... ) ; }
template < typename ... T > void wr ( T ... args ) {(( cout << args << " " ) , ... ) ; cout << '\n' ; }
int main () {
ios :: sync_with_stdio ( false ) ;
cin . tie ( nullptr ) ;
int n ;
cin >> n ;
vector < vector <int >> g ( n ) ;
struct node {
string name , has , wants ;
} ;
vector < node > a ( n ) ;
unordered_map < string , int> names , toys ;
unordered_map < string , string > wanted_by ;
for ( auto& [ name , has , wants ] : a ) {
cin >> name >> has >> wants ;
names . try_emplace (name , names . size ()) ;
toys . try_emplace (has , toys . size ()) ;
toys . try_emplace (wants , toys . size ()) ;
wanted_by [wants] = name ;
}
for ( int i = 0 ; i < n ; i ++ ) {
if ( wanted_by . count ( a [i] . has ))
g [i] . push_back ( names [ wanted_by [ a [i] . has ]]) ;
}
vector <int> vis ( n ) ;
int ans = 0 ;
auto dfs =[ & ] ( auto & dfs , int u , int dep ) -> void{
vis[u]=1;
for (auto v : g[u]) {
if ( vis [ v ] == 1 ) {
ans = max (ans , dep + 1 ) ;
} else {
dfs (dfs , v , dep + 1 ) ;
}
}
vis [ u ] = 2 ;
} ;
for ( int i = 0 ; i < n ; i ++ ) {
if ( ! vis [i]) {
dfs (dfs , i , 0 ) ;
}
}
if ( ans ) cout << ans ;
else cout << " No trades possible " ;
return 0 ;
}
还没来得及补
非常简单的矩阵乘法,队友写的,没要代码。。。
矩阵求逆,模运算下的高斯消元。队友赛后补的
using namespace std ;
# include < bits/stdc++.h >
# include < string >
# define ll long long
# define all ( x ) ( x ) . begin () , ( x ) . end ()
# define sz ( x ) int ( x . size ())
# define rep ( i , a , b ) for ( int i = a ; i < ( b ) ; ++ i )
# define FOR ( i , n ) for ( int ( i ) = 0 ; ( i ) < ( n ) ;++ ( i ))
# define PRE ( i , m , n , in ) for ( int ( i ) = ( m ) ; ( i ) < ( n ) ; i += in )
# define RPRE ( i , m , n , in ) for ( int ( i ) = ( m ) ; ( i ) >= ( n ) ; i -= in )
# define srt ( v ) sort ( v . begin () , v . end ())
# define printv ( a ) printa ( a , 0 , a . size ())
# define debug ( x ) cout << #x " = " << ( x ) << endl
# define printa ( a , L , R ) for ( int i = L ; i < R ; i ++ ) cout << a [ i ] << ( i == R - 1 ? "\n" : " " )
# define printv ( a ) printa ( a , 0 , a . size ())
# define print2d ( a , r , c ) for ( int i = 0 ; i < r ; i ++ ) for ( int j = 0 ; j < c ; j ++ ) cout << a [ i ][ j ] << ( j == c - 1 ? "\n" : " " )
typedef vector < string > VS ;
typedef pair <int , int> pii ;
typedef pair < ll , ll > pll ;
typedef vector < ll > VL ;
typedef vector <int> VI ;
typedef vector < VI > VVI ;
typedef vector < VL > VVL ;
typedef vector < pii > VII ;
const int MOD = 37 ;
const int INF = 2 ;
int gauss ( vector < vector < int > > & a , vector < int > & ans , const vector < ll > & inv ) {
int n = ( int ) a . size () ; int m = ( int ) a [ 0 ] . size () - 1 ;
vector <int> where ( m , - 1 ) ;
for ( int col = 0 , row = 0 ; col < m && row < n ; ++ col ) {
int sel = row ;
for ( int i = row ; i < n ; ++ i)
if ( a [i][col] > a [sel][col]) sel = i ;
if ( a [sel][col] == 0 ) continue ;
for ( int i = col ; i <= m ; ++ i)
swap ( a [sel][i] , a [row][i]) ;
where [col] = row ;
for ( int i = 0 ; i < n ; ++ i)
if (i != row) {
int c = ( a [i][col] * inv [ a [row][col]]) % MOD ;
for ( int j = col ; j <= m ; ++ j)
a [i][j] = ( a [i][j] - ( a [row][j] * c % MOD) + MOD) % MOD ;
}
++ row ;
}
ans . assign ( m , 0 ) ;
for ( int i = 0 ; i < m ; ++ i )
if ( where [ i ] != - 1 )
ans [ i ] = ( a [ where [ i ]][ m ] * inv [ a [ where [ i ]][ i ]]) % MOD ;
for ( int i = 0 ; i < n ; ++ i ) {
int sum = 0 ;
for ( int j = 0 ; j < m ; ++ j)
sum = (MOD + sum + ( ans [j] * a [i][j]) % MOD) % MOD ;
if ( abs (sum - a [i][m]) != 0 )
return 0 ;
}
for ( int i = 0 ; i < m ; ++ i )
if ( where [ i ] == - 1 ) return INF ;
return 1 ;
}
int main () {
ios_base :: sync_with_stdio ( false ) ;
cin . tie ( NULL ) ;
string ns ; getline ( cin , ns ) ; int n = stoi ( ns ) ;
string s1 ; getline ( cin , s1 ) ;
string s2 ; getline ( cin , s2 ) ;
vector < ll > inv ( MOD ) ;
inv [ 1 ] = 1 ;
for ( int i = 2 ; i < MOD ; ++ i ) inv [ i ] = MOD - ( MOD / i ) * inv [ MOD % i ] % MOD ;
vector < vector <int> > v1 ( n , vector < int > ()) ;
vector < vector <int> > v2 ( n , vector < int > ()) ;
for ( int i = 0 ; i < s1 . size () ; i ++ ) {
int num ;
if ( s1 [i] >= ' A ' && s1 [i] <= ' Z ' ) {
num = int ( s1 [i]) - 65 ;
}
else if ( s1 [i] == ' ' ) num = 36 ;
else num = ( s1 [i] - ' 0 ' ) + 26 ;
v1 [i % n] . push_back (num) ;
}
for ( int i = 0 ; i < s2 . size () ; i ++ ) {
int num ;
if ( s2 [i] >= ' A ' && s2 [i] <= ' Z ' ) {
num = int ( s2 [i]) - 65 ;
}
else if ( s2 [i] == ' ' ) num = 36 ;
else num = ( s2 [i] - ' 0 ' ) + 26 ;
v2 [i % n] . push_back (num) ;
}
int consistent = 0 ;
int many = 0 ;
int no = 0 ;
vector < vector <int> > sol ;
for ( int i = 0 ; i < n ; i ++ ) {
vector < vector <int >> a ( v1 [ 0 ] . size () , vector < int >(n + 1 )) ;
vector <int> b (n) ;
for ( int j = 0 ; j < v1 [ 0 ] . size () ; j ++ ) {
for ( int k = 0 ; k < n ; k ++ ) {
a [j][k] = v1 [k][j] ;
}
a [j][n] = v2 [i][j] ;
}
vector <int> ans ;
int num = gauss (a , ans , inv) ;
if (num == 0 ) no ++;
else if (num == 1 ) {
consistent ++;
sol . push_back (ans) ;
}
else many ++;
}
if ( consistent == n ) print2d ( sol , n , n ) ;
else if ( no >= 1 ) cout << " No solution " << endl ;
else if ( many >= 1 ) cout << " Too many solutions " << endl ;
return 0 ;
}
直接模拟即可
# include < bits/stdc++.h >
# define all ( x ) ( x ) . begin () , ( x ) . end ()
# define sz ( x ) int ( x . size ())
using namespace std ;
using ll = long long ;
using pii = pair < int , int > ;
template < typename ... T > void rd ( T & ... args ) {(( cin >> args ) , ... ) ; }
template < typename ... T > void wr ( T ... args ) {(( cout << args << " " ) , ... ) ; cout << '\n' ; }
int main () {
ios :: sync_with_stdio ( false ) ;
cin . tie ( nullptr ) ;
int n , m ;
cin >> n >> m ;
vector <int> a ( n ) , rank ( n ) ;
iota ( all ( a ) , 0 ) ;
iota ( all ( rank ) , 0 ) ;
while ( m -- ) {
char c ;
int u , v ;
cin >> c >> u >> c >> v ;
u --, v --;
if ( rank [u] > rank [v]) {
for ( int i = rank [v] ; i < rank [u] ; i ++ ) {
a [i] = a [i + 1 ] ;
rank [ a [i]] = i ;
}
a [ rank [u] + 1 ] = v ;
rank [v] = rank [u] + 1 ;
}
}
for ( auto i : a ) cout << " T " << i + 1 << ' ' ;
return 0 ;
}
根据 deadline 排序,然后维护有多少槽位可供不需要纸的和需要纸的人用(代码里的have
数组),不需要纸的人也可以用需要纸的人的槽位。然后根据人数相应的更新数组。
队友的赛时的源代码
from collections import *
from functools import *
from math import *
import sys
input = sys . stdin . readline
sys . setrecursionlimit ( 2147483647 )
ml = lambda : map ( int , input () . split ())
s , n = ml ()
people = defaultdict ( lambda : [ 0 , 0 ] )
for _ in range ( n ) :
deadline , need = input () . split ()
deadline = int ( deadline )
people [ deadline ] [ need [ 0 ] == " y " ] += 1
have = [ 0 , 0 ]
prev = 0
for deadline in sorted ( people . keys ()) :
have [ 1 ] += deadline - prev
have [ 0 ] += ( deadline - prev ) * ( s - 1 )
prev = deadline
dont , need = people [ deadline ]
do = min ( dont , have [ 0 ])
dont -= do
have [ 0 ] -= do
if dont + need > have [ 1 ] :
print ( " No " )
break
have [ 1 ] -= dont + need
else :
print ( " Yes " )
我用 C++ 又写了一遍:
# include < bits/stdc++.h >
# define all ( x ) ( x ) . begin () , ( x ) . end ()
# define sz ( x ) int ( x . size ())
using namespace std ;
using ll = long long ;
using pii = pair < int , int > ;
template < typename ... T > void rd ( T & ... args ) {(( cin >> args ) , ... ) ; }
template < typename ... T > void wr ( T ... args ) {(( cout << args << " " ) , ... ) ; cout << '\n' ; }
int main () {
ios :: sync_with_stdio ( false ) ;
cin . tie ( nullptr ) ;
int s , n ;
cin >> s >> n ;
map <int , array <int , 2 >> people ;
for ( int i = 0 ; i < n ; i ++ ) {
int deadline ;
char need ;
cin >> deadline >> need ;
people [deadline][need == ' y ' ] ++;
}
ll have [ 2 ]{} ;
int prev = 0 ;
for ( auto& [ deadline , v ] : people ) {
have [ 1 ] += deadline - prev ;
have [ 0 ] += ll (deadline - prev) * (s - 1 ) ;
prev = deadline ;
auto [dont , need] = v ;
int Do = min < ll >(dont , have [ 0 ]) ;
dont -= Do ;
have [ 0 ] -= Do ;
if (dont + need > have [ 1 ]) {
return cout << " No \n" , 0 ;
}
have [ 1 ] -= dont + need ;
}
cout << " Yes \n" ;
return 0 ;
}
还没补
根据题意模拟即可
# include < bits/stdc++.h >
# define all ( x ) ( x ) . begin () , ( x ) . end ()
# define sz ( x ) int ( x . size ())
using namespace std ;
using ll = long long ;
using pii = pair < int , int > ;
template < typename ... T > void rd ( T & ... args ) {(( cin >> args ) , ... ) ; }
template < typename ... T > void wr ( T ... args ) {(( cout << args << " " ) , ... ) ; cout << '\n' ; }
int main () {
ios :: sync_with_stdio ( false ) ;
cin . tie ( nullptr ) ;
vector a ( 9 , vector ( 9 , 0 )) ;
for ( auto& v : a ) for ( auto& i : v ) cin >> i ;
auto check_row =[ & ] ( int row , auto & cnt , int x ) {
for ( int i = 0 ; i < 9 ; i ++ ) {
cnt [row][i][x] = 0 ;
}
} ;
auto check_col =[ & ] ( int col , auto & cnt , int x ) {
for ( int i = 0 ; i < 9 ; i ++ ) {
cnt [i][col][x] = 0 ;
}
} ;
auto check_grid =[ & ] ( int r , int c , auto & cnt , int x ) {
int num = r / 3 * 3 + c / 3 ;
r = num / 3 * 3 , c = num % 3 * 3 ;
for ( int i = r ; i < r + 3 ; i ++ ) {
for ( int j = c ; j < c + 3 ; j ++ ) {
cnt [i][j][x] = 0 ;
}
}
} ;
auto count_row =[ & ] ( int row , auto & cnt , int x ) {
int c = 0 ;
for ( int i = 0 ; i < 9 ; i ++ ) {
if ( a [row][i]) continue ;
c += cnt [row][i][x] ;
}
return c ;
} ;
auto count_col =[ & ] ( int col , auto & cnt , int x ) {
int c = 0 ;
for ( int i = 0 ; i < 9 ; i ++ ) {
if ( a [i][col]) continue ;
c += cnt [i][col][x] ;
}
return c ;
} ;
auto count_grid =[ & ] ( int r , int c , auto & cnt , int x ) {
int num = r / 3 * 3 + c / 3 ;
r = num / 3 * 3 , c = num % 3 * 3 ;
int cc = 0 ;
for ( int i = r ; i < r + 3 ; i ++ ) {
for ( int j = c ; j < c + 3 ; j ++ ) {
if ( a [i][j]) continue ;
cc += cnt [i][j][x] ;
}
}
return cc ;
} ;
while ( true ) {
int found = 0 ;
vector cnt ( 9 , vector ( 9 , vector ( 10 , 1 ))) ;
for ( int i = 0 ; i < 9 ; i ++ ) {
for ( int j = 0 ; j < 9 ; j ++ ) {
cnt [i][j][ 0 ] = 0 ;
if ( a [i][j] != 0 ) {
check_col (j , cnt , a [i][j]) ;
check_row (i , cnt , a [i][j]) ;
check_grid (i , j , cnt , a [i][j]) ;
}
}
}
for ( int i = 0 ; i < 9 ; i ++ ) {
for ( int j = 0 ; j < 9 ; j ++ ) {
if ( a [i][j] == 0 ) {
if ( count ( all ( cnt [i][j]) , 1 ) == 1 ) {
found = 1 ;
auto it = find ( all ( cnt [i][j]) , 1 ) ;
a [i][j] = it - cnt [i][j] . begin () ;
goto next ;
}
for ( int v = 1 ; v <= 9 ; v ++ ) {
if (( count_col (j , cnt , v) == 1 || count_row (i , cnt , v) == 1 || count_grid (i , j , cnt , v) == 1 ) && cnt [i][j][v]) {
found = 1 ;
a [i][j] = v ;
goto next ;
}
}
}
}
}
next :
if (found == 0 ) break ;
}
int cc = 0 ;
for ( auto& v : a ) for ( auto i : v ) cc += i == 0 ;
if ( cc ) {
cout << " Not easy \n" ;
for ( auto& v : a) {
for ( auto& i : v) {
if (i == 0 ) cout << ' . ' ;
else cout << i ;
cout << ' ' ;
}
cout << '\n' ;
}
} else {
cout << " Easy \n" ;
for ( auto& v : a) {
for ( auto i : v) cout << i << ' ' ;
cout << '\n' ;
}
}
return 0 ;
}
我们可以用一次实验把当前问题变成两个更小的子问题,假设当前的最大高度是h
, 还剩n
个 pallet,如果我们用x
个箱子试一次,如果 pallet 坏了的话那么问题就变成了:最大高度为h-1
, 还剩n-1
个 pallet;如果没坏的话问题就变成了高度为h-x
,还剩x
个 pallet。所以我们可以用 dp。求范围的过程与 dp 类似。
# include < bits/stdc++.h >
# define all ( x ) ( x ) . begin () , ( x ) . end ()
# define sz ( x ) int ( x . size ())
using namespace std ;
using ll = long long ;
using pii = pair < int , int > ;
template < typename ... T > void rd ( T & ... args ) {(( cin >> args ) , ... ) ; }
template < typename ... T > void wr ( T ... args ) {(( cout << args << " " ) , ... ) ; cout << '\n' ; }
int main () {
ios :: sync_with_stdio ( false ) ;
cin . tie ( nullptr ) ;
int n , m ;
cin >> n >> m ;
vector need ( n + 1 , vector ( m + 1 , 0 )) ;
for ( int i = 0 ; i <= n ; i ++ ) need [ i ][ 1 ] = i ;
for ( int i = 1 ; i <= n ; i ++ ) {
for ( int pallet = 2 ; pallet <= m ; pallet ++ ) {
int mn = n + 1 ;
for ( int j = 1 ; j <= i ; j ++ ) {
int v1 = need [j - 1 ][pallet - 1 ] , v2 = need [i - j][pallet] ;
mn = min (mn , max (v1 , v2)) ;
}
need [i][pallet] = mn + 1 ;
}
}
int l = n , r = 0 ;
int ans = need [ n ][ m ] ;
for ( int i = 1 ; i <= n ; i ++ ) {
if ( max ( need [i - 1 ][m - 1 ] , need [n - i][m]) + 1 == ans){
l = min (l , i) ;
r = max (r , i) ;
}
}
cout << ans << ' ' ;
if ( l == r ) cout << l ;
else cout << l << ' - ' << r ;
return 0 ;
}
队友的二分做法:(和扔鸡蛋问题类似)
from collections import *
from functools import *
from math import *
import sys
input = sys . stdin . readline
sys . setrecursionlimit ( 2147483647 )
ml = lambda : map ( int , input () . split ())
def binomialCoeff ( x , n , k ):
sum = 0
term = 1
i = 1
while ( i <= n and sum < k ):
term *= x - i + 1
term /= i
sum += term
i += 1
return sum
def minTrials ( eggs , floors ):
if eggs == 0 :
return floors and inf
low = 1
high = floors
while low < high :
mid = low + high >> 1
if binomialCoeff ( mid , eggs , floors ) < floors :
low = mid + 1
else :
high = mid
return low
def findX ( eggs , floors ):
low = 1
high = floors
while low < high :
mid = low + high >> 1
if minTrials ( eggs , floors - mid ) <= ans - 1 :
high = mid
else :
low = mid + 1
return low
def findY ( eggs , floors ):
low = 1
high = floors
while low < high :
mid = low + high + 1 >> 1
if minTrials ( eggs - 1 , mid - 1 ) <= ans - 1 :
low = mid
else :
high = mid - 1
return low
# range: x to y
floors , eggs = ml ()
n = floors
m = eggs
# worst case: doesn't break on x and breaks on y
# find smallest x s.t. minTrials(floors - x, eggs) <= ans - 1
# find biggest y s.t. minTrials(y - 1, eggs - 1) <= ans - 1
ans = minTrials ( eggs , floors )
x = findX ( eggs , floors )
y = findY ( eggs , floors )
if x == y :
print ( ans , x )
else :
print ( ans , str ( x ) + " - " + str ( y ))
可以观察到一定是上面的几个门用 A 通道,剩下下面的用 B 通道,所以可以枚举 A 和 B 分界的位置,然后剩下的问题就是公寓匹配门、门匹配工作站了,跑两次二分图最大权匹配即可。之前做过匹配的题的话这题应该是很简单的,可以当时没人读到,但队友读了也不一定能反应过来是匹配问题 233。
# include < bits/stdc++.h >
# define all ( x ) ( x ) . begin () , ( x ) . end ()
# define sz ( x ) int ( x . size ())
using namespace std ;
using ll = long long ;
using pii = pair < int , int > ;
template < typename ... T > void rd ( T & ... args ) {(( cin >> args ) , ... ) ; }
template < typename ... T > void wr ( T ... args ) {(( cout << args << " " ) , ... ) ; cout << '\n' ; }
template < typename T >
class Hungarian {
public :
int n , m ;
vector < vector < T > > a ;
vector < T > u , v ;
vector <int> pa , pb , way ;
vector < T > minv ;
vector <bool> used ;
T inf ;
Hungarian ( int _n , int _m ) : n (_n) , m (_m) , a (n , vector < T >(m)) , u (n + 1 ) , v (m + 1 ) , pa (n + 1 , - 1 ) , pb (m + 1 , - 1 ) , way (m , - 1 ) , minv (m) , used (m + 1 ) {
assert (n <= m) ;
inf = numeric_limits < T > :: max () ;
}
inline void add_row ( int i ) {
fill ( minv . begin () , minv . end () , inf) ;
fill ( used . begin () , used . end () , false ) ;
pb [m] = i ;
pa [i] = m ;
int j0 = m ;
do {
used [j0] = true ;
int i0 = pb [j0] ;
T delta = inf ;
int j1 = - 1 ;
for ( int j = 0 ; j < m ; j ++ ) {
if ( ! used [j]) {
T cur = a [i0][j] - u [i0] - v [j] ;
if (cur < minv [j]) {
minv [j] = cur ;
way [j] = j0 ;
}
if ( minv [j] < delta) {
delta = minv [j] ;
j1 = j ;
}
}
}
for ( int j = 0 ; j <= m ; j ++ ) {
if ( used [j]) {
u [ pb [j]] += delta ;
v [j] -= delta ;
} else {
minv [j] -= delta ;
}
}
j0 = j1 ;
} while ( pb [j0] != - 1 ) ;
do {
int j1 = way [j0] ;
pb [j0] = pb [j1] ;
pa [ pb [j0]] = j0 ;
j0 = j1 ;
} while (j0 != m) ;
}
inline T current_score () {
return - v [m] ;
}
inline T solve () {
for ( int i = 0 ; i < n ; i ++ ) {
add_row (i) ;
}
return current_score () ;
}
} ;
int main () {
ios :: sync_with_stdio ( false ) ;
cin . tie ( nullptr ) ;
int n ;
cin >> n ;
vector g1 ( n , vector ( 2 * n , 0 )) ;
auto g2 = g1 ;
for ( auto& v : g1 )
for ( auto& i : v ) cin >> i ;
for ( auto& v : g2 )
for ( auto& i : v ) cin >> i ;
int mn_cost = 1 e 9 ;
vector < array <int , 3 >> ans ( n ) ;
for ( int i =- 1 ; i < n ; i ++ ) {
vector ng1 (n , vector (n , 0 )) ;
auto ng2 = ng1 ;
for ( int j = 0 ; j < n ; j ++ ) {
for ( int u = 0 ; u < n ; u ++ ) {
ng1 [u][j] = g1 [u][j * 2 + (j > i)] ;
ng2 [u][j] = g2 [u][j * 2 + (j > i)] ;
}
}
Hungarian <int> h1 (n , n) , h2 (n , n) ;
h1 . a = ng1 , h2 . a = ng2 ;
if ( int cur = h1 . solve () + h2 . solve () ; cur < mn_cost) {
mn_cost = cur ;
for ( int j = 0 ; j < n ; j ++ ) {
ans [j] = {j , h1 . pa [j] * 2 + ( h1 . pa [j] > i) , h2 . pb [ h1 . pa [j]]} ;
}
}
}
cout << mn_cost << '\n' ;
for ( auto [ x , y , z ] : ans ) {
cout << x + 1 << ' ' << y / 2 + 1 << char ( ' A ' + y % 2 ) << ' ' << z + 1 << '\n' ;
}
return 0 ;
}