- 积分
- 16841
在线时间 小时
最后登录1970-1-1
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?开始注册
x
算法 {算法代码模板,算法模板编写规范}% W- R9 }4 {6 X: R! \# y& a. m
supimoTemplate.cpp
3 F2 `! Q0 G) g% |/ F8 Y代码
, O; _7 B" h% o% D' B# n#define ___SUPIMOenvir_! j" }! @9 U& B. |% J" r5 a$ k
( x0 Y) L* m' q+ F/ |6 K3 z#include <bits/stdc++.h>
: X$ i$ c& w% N1 _0 pusing namespace ::std;$ G* a" {: f' Y8 Z$ Y& m
+ e* z4 {3 l6 W7 Z0 d0 |
#ifdef ___SUPIMOenvir_
. y5 n6 K8 k1 h #include "supimoDebug.hpp"
- L, m) n& q) f#else
- m- ~8 y0 E, \6 Q t" ] #define TOstringITEMS_( ...) ""' N; t/ e/ Q; j6 \' e6 B: }
#define DE_( ...)! E9 L7 ~$ r" F) \. T
#define ASSERTcustom_( _op, ...) assert(_op)
2 n- t5 X& @5 D0 _& L #define ASSERTsystem_( _op, ...) assert(_op)
. k" s0 @& ^& W) o S$ v. a. G#endif
\7 [- R5 N( ]3 \/ |7 U' ^( M* O8 W+ B& Q% Q4 n
#define ASSERTregion_( ...) __VA_ARGS__7 o. g2 m, K4 ~* L3 d: Y
#define ASSERTsentence_( ...)0 y$ C6 y w8 ?3 }
#define EXIT_ std::cerr<< "\nExit(2267): Line("<< __LINE__<< ")\n"; std::exit(2267);
8 ^- J# E/ c: J6 ]#define EXITcounter_( _max) { static int cont = 0; ++ cont; if( cont == _max){ string str = "Exit_Counter(" + std::to_string(_max) + ")"; DE_(str); EXIT_;}}
( L$ p$ |5 R5 ~4 S#define FOR_( _i, _l, _r) for( int _i=int(_l); _i<=int(_r); ++_i)# W2 F7 L m; k J. b9 e
#define FORrev_( _i, _l, _r) for( int _i=int(_l); _i>=int(_r); --_i)
- t: l, a- y- }# Z" g: a" }) {7 ` ^5 \" r: k. l
using Int64_ = long long;) ]5 R7 s( i" F9 |5 T+ _) e
& Q+ c) J# Y# g7 }
3 g8 m% ?; v V9 B2 ?9 o, Q/ e
void ___Solve_oneTest(){( k; C9 [0 w# `7 u
}# s% S! n# D0 E; V1 q
void ___GlobalInitialze(){
; ]- s# o' x: C- s0 Y}
. @+ [6 T2 z& Kint main(){0 j$ H$ b4 E/ N8 t! L& a+ _# m: J
std::ios::sync_with_stdio(0); std::cin.tie(0);$ P3 A, K% L) h8 t6 D9 S; K
std::cerr.setf( std::ios::fixed); std::cerr.precision( 9);
" _" v7 |4 B/ x G% V2 o std::cout.setf( std::ios::fixed); std::cout.precision( 9);, @% s" S5 n& B2 _" L$ o- r
$ R! U$ r) g- x8 E; J6 o- S auto ___Solve = [](){ // Problem-Input4 B( M8 H# O5 I% x7 P
constexpr char MODEisSINGLE = 1;
6 [$ R2 ]- N/ C6 i# t. n. v int testsCount;# k7 w+ ]" Q X$ b( w: \
if( MODEisSINGLE){ testsCount = 1;} else{ cin>> testsCount;}
7 K- Q- _ J, i3 r; s for( int id = 0; id < testsCount; ++id){
0 |) _. i" @( x1 W4 d( U6 ` if( id == 0){ ___GlobalInitialze();}
, K6 r' @. L$ A# s- L ___Solve_oneTest();
4 B7 b0 M, d6 j' V, S a! K# m }+ }) o8 e2 P" k$ i
};
& {0 ], r; Z/ G8 W- b: S#ifdef ___SUPIMOenvir_3 o4 m' c: U/ x) X* x
while( 1){( q+ \ c" S8 j' m6 ?& A3 i6 g
std::string flag; std::cin>> flag; ASSERTsystem_( flag.substr( 0, 10) == "#___Input[", flag);
( o1 m& n9 T5 z& e+ i flag.replace( 4, 2, "Out");
& {# P1 _2 d+ h1 g6 Y std::cout<< " "<< flag<< "\n"; std::cerr<< " "<< flag<< "\n";
8 e {3 [( x4 v if( flag == "#___Output[-1]#"){ break;}
- \7 N) j9 `) c9 y+ Y// int timeStart = std::clock();
) p6 B' B2 N4 \8 H+ @ ___Solve();( L2 a1 C+ T/ Y' d$ ]1 E% O, i' S5 H
std::cout<< "\n"; std::cerr<< "\n";
; _- ?, c4 U6 x4 g5 |, G) ^// std::cout<< "TimeElapsed: "<< std::clock() - timeStart<< "\n";% v& K- i0 n2 z9 }; \1 p6 N
}2 Y8 [) h: V# n( z& l
#else
$ r5 a+ v2 y0 }6 b0 z" |; n$ J/ q ___Solve();/ n5 b: ~# E6 t4 G* b/ X) b# B9 t
#endif
; u( U8 [! r2 n% V. x7 l) T, _" ^ ?" Q
return 0;2 C. o2 A" M" |0 j4 L
}/ {# k7 ^& {1 e8 L" K5 r: w6 e
11 B( d' \, \* q! v$ y4 P
2
$ d' c3 N0 `7 j5 x# @; G6 K3: P9 K' x5 I" q
48 ]/ v% i) e2 V% m% l
5+ }) I* j# G1 e/ n& F
6- l/ a# R& }: d, b# ]; a4 D# B7 U
7( }: v3 G( h" _4 p, B, V) N: x9 N9 G
8* F7 o) u+ Q% \$ ?
9* \4 L8 @& O8 U$ s/ D
109 H" }/ l7 _/ q$ Y4 U. g& b
116 }$ U, b' x! D( w& n y
12% S: k0 R( e8 [6 e7 I7 M* E1 l
133 e4 `! y1 F/ [- f F
14
' j/ _2 P9 ]3 B2 `' b15
1 {* n+ A4 m$ {7 @- l16
6 [, V: p* N: q$ S+ k1 c( K0 F' M9 T7 G17
; j, ^5 q: M) o9 j5 V8 s) _18
) i; }3 Z- [5 [4 a3 X1 m% Q- _19
6 O, b# y' n" X7 \$ i# e- p% U20
$ k3 q4 N1 |! M) U6 q- g8 c( ^2 f21: L+ N/ R. K, `- C
22
3 a: n* G$ n5 J+ V) `6 k. `23
8 R. t" t% [# U+ U24* |; e4 n! a1 S3 T- q! i
25) }# G" ^/ ]+ c5 O
261 `% X* A4 S9 e( U+ C' S
27
; O! p+ Z! O9 o, q$ g( V4 I28
0 x9 B( |! ~# H7 H29
2 X }9 K+ b) |( C' D2 Q; a) r30
& [4 ?) }5 j2 {" @9 D3 \* _% L31% g, p+ d" ?' A% \* |8 r# n5 Y
32$ A* \* E) P8 s/ }+ @
339 p' e2 @: J; N
34, ?! Z( x! G @! v
35+ Z$ v0 L5 ^+ R- W# J
36
E5 Q6 l# I; y) r, ^# [7 F37
1 c% P6 j9 `0 d& i- I$ D6 v, `+ P380 n4 N( H; U3 q1 N4 y
39, W9 f% ~# [* U1 T% }
40
8 x! f. K8 G* ]! i# T2 T5 S41- m2 ^1 x/ h8 }
42+ O9 ^5 H5 j) t3 f, n+ C3 n
43
. w' l" ~" ]+ ]% E3 E0 m( b4 W44( G6 X, b: Y5 U
45. h# |7 V+ }3 u
46
k% W9 v: j& w2 \7 b& ]7 \47) N" ?7 \0 b& p9 X2 | E, w, M
48
8 L& \& X3 b4 ~8 J$ y* N; D' j6 U49. P/ f4 D* h s+ L; O8 D" R
505 T6 p& d# W0 @* g* r
51
/ m" B; m% C0 u) \1 n5 o/ z7 V: R: ~52# a- M+ I+ k3 Z0 W* t; r# A6 Z$ g
53) a6 x1 x% [" J X5 p
54$ c0 ^+ g7 Y/ c! t' Q
55
. K! J0 J. g/ {8 X56$ G8 L& e. X; S( x. ~+ s
57* F1 a& S( Q( y
58
8 }, E6 x0 n% q8 v8 P5 e+ E7 X; s W59; |+ ^, ^% y% ~; Q# u; Q3 J! D
supimoDebug.hpp2 o4 l& ~4 N6 y: m/ @* H& z
代码
7 k, x! x$ J& }. L T r3 w#include <bits/stdc++.h>
- _- r5 l* T% f9 T6 x, Z$ r+ Y$ v0 v0 C8 E, ^+ }1 F# O7 z, J
#define VARSandLOCATION_( ...) std::string(std::string("{File: ")+ __FILE__+ ", Line: "+ std::to_string(__LINE__)+ ", VarName: ["+ #__VA_ARGS__+ "]}")1 ^3 p7 e, [, r7 ^: `9 q
#define TOstringITEMS_( ...) ___DEBUG_::ToString_Items( __VA_ARGS__)% Q. ^* P0 p5 Z9 j R4 V$ t
#define DE_( ...) std::cerr<< TOstringITEMS_( __VA_ARGS__)<< " "<< VARSandLOCATION_(__VA__ARGS__)<< "\n"
7 l: F g' s. Z#define ASSERTcustom_( _op, ...) if( !bool(_op)){ std::cerr<<"Assertion_Failed(Custom): ["<< #_op<< "] {Hint: ["<< TOstringITEMS_( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< "); Line: "<< __LINE__<< "}"; std::exit(2267);}8 i' z* I9 G$ M3 }
#define ASSERTsystem_( _op, ...) if( !bool(_op)){ std::cerr<<"Assertion_Failed(System): ["<< #_op<< "] {Hint: ["<< TOstringITEMS_( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< "); Line: "<< __LINE__<< "}"; std::exit(2267);}
& C& Q3 \* \8 q$ t+ ]7 @, Z+ E' z. f
namespace ___DEBUG_ {
9 I0 N9 c% y& @* O% p //>> 所谓`Container`是指 可以通过`for( auto i : S)`来进行遍历的;& w' p! f L# A$ I# J, I
template< class _t> struct __IsContainer_Unwrap : std::false_type{};) w, ^4 F% @" r, p) j
template< class _t> struct __IsContainer_Unwrap<std::vector<_t> > : std::true_type{};, t0 @+ u$ b C' |) [4 q
template< class _t> struct __IsContainer_Unwrap<std::set<_t> > : std::true_type{};
0 E# X; d& p; i; _! b: H9 J' W template< class _t> struct __IsContainer_Unwrap<std::unordered_set<_t> > : std::true_type{};1 |6 f5 b0 ^* n
template< class _t> struct __IsContainer_Unwrap<std::multiset<_t> > : std::true_type{};; q4 w, {) j" R) v8 O) L) O j
template< class _t> struct __IsContainer_Unwrap<std::unordered_multiset<_t> > : std::true_type{};7 ~% f8 k4 N* P! c
template< class _t0, class _t1> struct __IsContainer_Unwrap<std::map<_t0,_t1> > : std::true_type{};
* O, _4 r% P! i template< class _t0, class _t1> struct __IsContainer_Unwrap<std::unordered_map<_t0,_t1> > : std::true_type{};
# ~+ m4 j/ {# v( u. P' @2 B4 Z template< class _t0, int _t1> struct __IsContainer_Unwrap< _t0[_t1] > : std::true_type{};4 G% z# X' X( }8 K# B( d+ R, t8 b
template< int _t1> struct __IsContainer_Unwrap< char[_t1] > : std::false_type{}; // 特判, 字符串常量"..."不属于容器;
& @5 \, a0 R( ]7 W S! Q9 T template< class _t> struct IsContainer : __IsContainer_Unwrap<std::remove_const_t<std::remove_reference_t<_t> > >{}; // 不能用`decay` 否则`T[N]`就退化为`T*`了;8 _" C: z, P$ j J) }8 k2 k
( d0 n" y7 f* ]: w+ P1 p6 O template< class _t> struct __IsPair_Unwrap : std::false_type{};! M! s: u: N$ ^7 b; D6 h: j7 N( V
template< class _t0, class _t1> struct __IsPair_Unwrap< std::pair<_t0,_t1> > : std::true_type{};
! s" Z9 N5 O: c' h template< class _T> struct IsPair : __IsPair_Unwrap< std::decay_t<_T> >{};
& T1 _6 g8 B" r8 |
* ?, ?/ A/ Z7 F+ k! i% [- r template< class _t> struct __IsStack_Unwrap : std::false_type{};+ M" B/ f) X8 r7 p
template< class _t> struct __IsStack_Unwrap< std::stack<_t> > : std::true_type{};
7 L0 `. f0 |/ ^8 M4 N4 g7 @ template< class _T> struct IsStack : __IsStack_Unwrap< std::decay_t<_T> >{};5 l U0 a; N6 j* ~
, ~: D4 D; {0 R" \' g
template< class _t> struct __IsQueue_Unwrap : std::false_type{};* g' E+ i. B: ?! L
template< class _t> struct __IsQueue_Unwrap< std::queue<_t> > : std::true_type{};, h" U, H' }8 V6 s- b
template< class _T> struct IsQueue : __IsQueue_Unwrap< std::decay_t<_T> >{};
. a+ e+ f Z# h
$ |, V8 m8 r2 P+ s template< class _t> struct __IsDeque_Unwrap : std::false_type{};3 T1 S# f3 E2 ]4 F$ B
template< class _t> struct __IsDeque_Unwrap< std::deque<_t> > : std::true_type{};- T# l1 G5 w: d& i9 s
template< class _T> struct IsDeque : __IsDeque_Unwrap< std::decay_t<_T> >{};
* M2 s4 v- K4 Z& `7 ?( p
0 b r+ F! ~' f1 ~+ h/ ? template< class _T> std::string ToString( _T const&);
5 z7 ^) }! m1 V
. r8 s1 R+ I0 O6 E0 Q template< class _T, int _Check> struct __ToString_Category;
6 l5 Y# H% }8 [2 g, \! @$ N2 } template< class _T> struct __ToString_Category<_T, 0>{ // Single
! R+ i6 a3 x( C7 u/ \1 q$ K template< class _t> static std::string TOstring( _t const& _v){8 f) W4 e0 ~' m/ i0 K
std::ostringstream ANS; ANS.precision( std::cout.precision()); ANS.setf(std::cout.flags()); ANS<<_v;
. y% a: L# n1 {. B return ANS.str();+ }/ l. N5 v, t5 Z
}$ c8 W* p0 O6 b4 A; j, h
static std::string TOstring( unsigned __int128 const& _v){ auto v = _v; std::string ANS; if(v==0){ ANS="0";} else{ for(;v!=0;v/=10){ ANS+=('0'+v%10);} std::reverse(ANS.begin(), ANS.end());} return ANS;}' I6 B% b2 h: n6 d9 I2 {3 _
static std::string TOstring( __int128 const& _v){ std::string ANS; auto v = _v; if(v==0){ ANS="0";} else{ if(v<0){ ANS+="-"; v=-v;} for(;v!=0;v/=10){ ANS+=('0'+(v%10));} std::reverse(ANS.begin()+(ANS[0]=='-'?1:0), ANS.end());} return ANS;}
9 c- s% v( A( h% i& r; q! M static std::string TOstring( bool const& _b){ return (_b?"1":"0");}
: S$ S# I! c% d2 P8 ]* U static std::string TOstring( char const& _a){2 y* b' S8 _8 C9 }. J
if(_a==0){ return "'\\0'";} // 否则因为她是*结束控制符* 会导致`ostream<<char(0)<<A;`后面的`A`不输出了;4 Z% Y1 t! g7 y% u! p) n
std::string ANS="'?'"; ANS[1]=_a; return ANS;
3 c+ S) P' O' t1 \: u" D- ? o }
) X9 V9 |: ]% N `( p; G$ t static std::string TOstring( char const* const& _s){ return std::string(_s);}
: o: x1 x+ S6 }& P static std::string TOstring( std::string const& _tt){ std::string ANS="\""; ANS+=_tt; ANS+='\"'; return ANS;}, W+ I1 d1 o; }
};
/ ~. _9 c) B$ y# @& F template< class _T> struct __ToString_Category<_T, 1>{ // Container: ^. k3 X0 r6 B: |+ R
template< class _t> static std::string TOstring( _t const& _v){
5 P4 M- U: Q$ |2 g, j std::string ANS="["; bool first=1;5 T/ \ Q( P( S( }& @* H R
for( auto const& i : _v){ if( 0==first) ANS+=","; if( first) first=0; ANS+=ToString(i);}: o& P* U: J# Z+ ~5 }: t n
ANS+="]";
& F5 U5 ^4 a4 M; A8 t5 V return ANS;& w) \; H" T! g) Q+ s* |; I
}2 }# h" v$ y6 C# o! a8 v
};# m# B* Z. P6 Q {2 `) e2 [* [
template< class _T> struct __ToString_Category<_T, 2>{ // Pair
3 y {; Y0 S U* M- i template< class _t> static std::string TOstring( _t const& _v){ std::string ANS="("; ANS += ToString(_v.first); ANS+=","; ANS+=ToString(_v.second); ANS+=")"; return ANS;}
* C( [. s* d' j# O m };
: c) H/ Y7 T3 m. U1 \: c) ? template< class _T> struct __ToString_Category<_T, 3>{ // Stack2 H& d7 V+ C% D0 U- j0 Z! ^0 r: ^4 q: G% Q
template< class _t> static std::string TOstring( _t const& _v){ std::string ANS="Stack(top)["; auto t = _v; for( bool first=1; t.empty()==0; t.pop(), first=0){ if(first==0){ ANS+=",";} ANS += ToString(t.top());} ANS+="]"; return ANS;} V0 e/ o( s/ E, ^. W# [
};
, q& r) |& a1 z template< class _T> struct __ToString_Category<_T, 4>{ // Queue) Q$ \3 d, k( O3 V2 D
template< class _t> static std::string TOstring( _t const& _v){ std::string ANS="Queue(front)["; auto t = _v; for( bool first=1; t.empty()==0; t.pop(), first=0){ if(first==0){ ANS+=",";} ANS += ToString(t.front());} ANS+="]"; return ANS;}+ B" Y$ R( _8 a6 C; _7 w
};3 m X- M" O- h4 Y% P4 I
template< class _T> struct __ToString_Category<_T, 5>{ // Deque2 S1 x( w; c) Z3 p
template< class _t> static std::string TOstring( _t const& _v){ std::string ANS="Deque(front)["; auto t = _v; for( bool first=1; t.empty()==0; t.pop_front(), first=0){ if(first==0){ ANS+=",";} ANS += ToString(t.front());} ANS+="]"; return ANS;}1 l% ?* p6 s+ k: D9 }
};
. U% I1 B$ w! i! z1 h! m, y v- W0 X/ ^& w
template< class _t> struct __ToString : __ToString_Category<_t, (IsContainer<_t>::value ? 1:(IsPair<_t>::value ? 2:(IsStack<_t>::value ? 3:(IsQueue<_t>::value ? 4:(IsDeque<_t>::value ? 5:0)))))>{};
. z9 m) W4 J. }$ C, g" l- J7 ^% y& y
template< class _t> std::string ToString( _t const& _v){ return __ToString<_t>::TOstring(_v);}2 V' Z6 N& l! P! W( Y) [3 N+ v) x
- E. F7 Z* O: p$ g
template< class... _H_> std::string ToString_Items( _H_ const&...){ return "";}
; @" R3 I9 g( q- I$ K template< class _H_> std::string ToString_Items( _H_ const& _h){ return ToString(_h);}
J E/ P; k. n! Y: x% n( Q6 q template< class _H_, class... _T_> std::string ToString_Items( _H_ const& _h, _T_ const&... _t){ std::string ANS; ANS+=ToString( _h); ANS+=", "; ANS+=ToString_Items( _t...); return ANS;}: w1 U. `; c& ~( j) |0 H. g" \
}. M4 ^! T8 r C& e1 t
3 T, W Q5 }: P5 F& U5 o
1
' s% }; ]" C! T! T6 n2- f% Z9 t/ V: ]/ f9 y
3& h' K0 U0 Q- J
4
1 n' O+ }9 o( I5
5 Q* g7 D0 y8 _& W$ B6 E; v1 K, G P) ^8 D6 o
7% E- S T7 @; v1 N1 L
8
6 T' _8 D: c/ X0 _) z {9
5 _% {2 f$ _2 e10/ t2 T& q! M' {8 d3 h$ K( ~
11" `7 C) u5 [8 Z# k, {+ ^: S- \
12
5 p8 y) {! }% a13: \* T* s! }) e& k0 O) h; d' N" A
14
; c1 C U, O. Q% X' T15
0 M! ]/ A( z: V. h: g169 B# B; H9 `' c6 K
17* c1 i/ f2 |: G. x( w$ e
18
( _7 |& S' i5 I/ M- x8 x19& ]% v T5 X \. Q
202 }1 D2 f1 A* C8 c3 ~
21& M6 |. u* l9 R# m9 h$ _! O
22
5 L7 [% Q$ ]4 Z. m4 w* d23$ W8 t( T8 a0 g( K" R# H
24. v7 C% y7 e/ p. T. `& ^/ r% k
25& m( }: K c! D; K7 ~
26; F% ?, I. g2 L( F8 p$ @- h* \
27: x6 B- \$ |. N5 z* g5 v( b
28
2 Y( @! z% f& y6 z3 }" s$ E3 K29! V0 U+ ^! }9 D1 O
30
: P- \$ b3 B8 i31
9 ]/ }3 r# {0 V, H5 T) ?% J32
7 P4 Q. z+ n7 x& ^% U33+ {( C/ Q3 n( D. Q0 V" M
34
3 O/ Q; S1 S5 S) j# u35( Y) u& ]8 O6 R& t! l( u* H6 m: P' u
36, r f( j4 Q* t9 F% ^ p* n# w6 J
37
% `7 a: \6 f1 C& ~; `# }9 q. C38. O+ M: o) ~. s$ P$ Y
39, j9 i) _2 x2 R1 H( W4 T
40
; R6 J2 e! u, e) ] L, m' Q t( a41
3 O' M, f" F! G) C5 b# @& ?) v, J421 _( x2 o' ~2 l9 x* ]3 [
43
0 h1 s4 y3 W& t, M448 m* A9 V6 Y" v9 ?! j
45) ~3 `# z$ b) e2 n, q
46
" }4 b7 }) V6 I1 m3 W! X! Q47; j5 h" k# R3 @
48
& _* Q$ o H8 B) w49! M( z6 r- U: d
50- ?! p6 }8 J! h0 G+ c, P$ d" I
51
: w0 c8 C/ j' f$ f. m8 _52; M I. A3 n- ]) D
53" J& p7 v! v$ G. N
54
N! a9 Z x5 j, t+ X555 s- ^% A: E. V$ d
56' X& ^6 k: U6 U
57
- u0 H$ F8 Q$ \" i$ ]58
9 k- H/ b& f# s- D6 b3 {59
) k9 [% m+ s; H, M/ v% d/ s0 {# c# k600 B# p1 b$ R8 z w. U" i
61( v( c" t. ]2 u) w0 X/ T
62" b* Y6 l& D* p; @5 U- {# p" \
63+ B* F; `3 _/ p) v2 Q9 N0 V
64. U8 _/ \, O+ k0 o5 f5 m# z
65
v: ~# x, D+ Y0 E1 g/ u66
+ `, |, r8 a8 {* _5 q67
/ R5 M2 b6 E4 V3 A) W% v* r688 J0 r( a8 ]4 g
699 i& a6 J) |+ {2 P7 o1 ]
709 A8 X6 `9 B9 M7 @! k( _
71: _9 g" b* v& L, e# T* `( _% i
72
. ?8 D( g9 g; i4 U9 l2 X0 D3 ?73
. N* G9 u( p6 g% K; ?2 E3 N74
/ W4 R! m) y! f( Q Q75
* `& J1 }; {' q9 ]1 y76- {. h% W' g4 g0 T
77) l- J+ V4 V6 R" V) p* Q
78# g* F5 T( I" d* q# m1 z8 _3 M
79$ C" C/ V7 C# p# C
80
+ M' y7 L! P6 n/ K% V& y/ v( A8 R81- }: m( S- f3 a
82
7 `- ?/ x( }' o5 O' ]4 `9 A$ X830 `6 C+ D8 B1 w5 ]0 _/ t
841 _1 `6 u& p/ P4 z) M/ z J
85
" c: }. |& i$ L0 N4 U) F86
2 p" q$ m2 H7 o' O4 h2 P) b& V1 G性质. d8 j6 v$ E" P4 o
#TOstringITEMS_#" r( J7 _, m/ l
这个宏 是为了: 对类进行输出时 可以直接_cout<< TOstringITEMS_(成员变量...);
) N* O% K) v3 |1 C D$ B' }你可能认为, 直接_cout<< ___Debug_::ToStringItems(...)不就行了?
, W) S0 c7 s4 x8 z. q. 错误, 因为在最终文件里 是看不见___Debug_的, 所以写成一个宏 在最终文件里 #define TOstringITEMS_ "";
- H, `; c N( o& b; T
( b2 I3 F0 d8 B+ I4 ]* M6 R笔记' g8 E' C0 }4 g
#以前的debug.hpp#
! s4 T- b" y, d7 F D5 j
; P3 [7 f5 g/ ]2 Y6 ~& V" m//{ omipusDebug.hpp
4 C0 b% _1 A6 t. { E/ @#include <bits/stdc++.h>
* g- m& F) D3 y @# l3 M. K
0 w1 U( j2 L* [) ^#define TOstringITEMS_( ...) ___DEBUG_::ToString_Items( __VA_ARGS__)
4 @/ O" G3 p. d# L$ O8 \! C#define DE_( ...) std::cerr<< TOstringITEMS_( __VA_ARGS__)<< " "<< "{"<< "Line: "<< std::to_string(__LINE__)<< ", Var: ["<< (#__VA_ARGS__)<< "]"<< "}"<< "\n"
. r( L7 t9 K5 K3 x& l8 L#define ASSERT_( _op, ...) if( !bool(_op)){ std::cerr<<"Assertion: ["<< #_op<< "] {Info: ["<< TOstringITEMS_( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< "); Line: "<< __LINE__<< "}"; std::exit(2267);}
3 Z2 h5 z. p% J: n#define ASSERTsystem_( _op, ...) if( !bool(_op)){ std::cerr<<"Assertion(System): ["<< #_op<< "] {Info: ["<< TOstringITEMS_( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< "); Line: "<< __LINE__<< "}"; std::exit(2267);}
' N3 l$ m. t& I* T! k0 |( D1 \9 L8 n4 E1 i) \% P/ ]* u) J
namespace ___DEBUG_ {: I1 t0 ]' Y7 E4 J3 [4 X
template< class _t> struct __IsContainer_Unwrap : std::false_type{}; // 所谓`Container`是指 可以通过`for( auto i : S)`来进行遍历的;
, e9 C! D# j' t7 L* d template< class _t> struct __IsContainer_Unwrap<std::vector<_t> > : std::true_type{};0 C: h& I4 R4 F! I2 Q4 @% \5 w- v
template< class _t> struct __IsContainer_Unwrap<std::set<_t> > : std::true_type{};
( M4 K+ X) m" L- j4 D# U template< class _t> struct __IsContainer_Unwrap<std::unordered_set<_t> > : std::true_type{};+ t2 o, i5 q! U$ v
template< class _t> struct __IsContainer_Unwrap<std::multiset<_t> > : std::true_type{}; }0 G9 ?% F5 j t
template< class _t> struct __IsContainer_Unwrap<std::unordered_multiset<_t> > : std::true_type{};
, A: |7 Z( n8 j, o6 ^+ q$ ` template< class _t0, class _t1> struct __IsContainer_Unwrap<std::map<_t0,_t1> > : std::true_type{};
2 b1 F' E3 A& g. d7 P# i2 m8 b+ f template< class _t0, class _t1> struct __IsContainer_Unwrap<std::unordered_map<_t0,_t1> > : std::true_type{};, e* j8 |, T8 g- w0 T$ o% @+ c
template< class _t0, std::size_t _t1> struct __IsContainer_Unwrap< _t0[_t1] > : std::true_type{};
0 I1 [6 f& V' Y6 ~ template< std::size_t _t1> struct __IsContainer_Unwrap< char[_t1] > : std::false_type{}; // 特判, 字符串常量"..."不属于容器;
! W. o1 r* a* h; J template< class _t, std::size_t _siz> struct __IsContainer_Unwrap<std::array<_t,_siz> > : std::true_type{};( f# e2 i1 @: ?; x) Y
template< class _t> struct IsContainer : __IsContainer_Unwrap<std::remove_const_t<std::remove_reference_t<_t> > >{}; // 不能用`decay` 否则`T[N]`就退化为`T*`了;# H9 V7 L* c# D) i _) j
8 i9 P2 y% g0 P; Z" Q( h! A' w template< class _t> struct __IsPair_Unwrap : std::false_type{};
+ L" F0 K* l b2 Q; w template< class _t0, class _t1> struct __IsPair_Unwrap< std::pair<_t0,_t1> > : std::true_type{};# s7 p2 e# Y7 X. j
template< class _T> struct IsPair : __IsPair_Unwrap< std::decay_t<_T> >{};0 c% d+ |8 C" X2 O; `' a& n/ F
' T& s: `1 a; b W, n8 i$ I
template< class _t> struct __IsStack_Unwrap : std::false_type{};: u4 Y4 x* l9 ]0 x: N3 g* M
template< class _t> struct __IsStack_Unwrap< std::stack<_t> > : std::true_type{};2 ~- A+ V7 z; k6 U y4 u0 o( c
template< class _T> struct IsStack : __IsStack_Unwrap< std::decay_t<_T> >{};
/ X+ `7 Z% C* b. j4 N" j5 r5 @7 m9 e: u5 c* _% [
template< class _t> struct __IsQueue_Unwrap : std::false_type{};' a3 I1 _/ H5 o3 O$ W& z6 u
template< class _t> struct __IsQueue_Unwrap< std::queue<_t> > : std::true_type{};
* H' A( }) u2 w9 w- w: t. d template< class _T> struct IsQueue : __IsQueue_Unwrap< std::decay_t<_T> >{};) a( K1 Z% l+ d1 c
/ \" }; |3 M( ]6 C( g
template< class _t> struct __IsDeque_Unwrap : std::false_type{};" `* B& a" l. g6 u. Q" J
template< class _t> struct __IsDeque_Unwrap< std::deque<_t> > : std::true_type{};0 X0 I9 J; u3 \
template< class _T> struct IsDeque : __IsDeque_Unwrap< std::decay_t<_T> >{};7 R- n- W- L6 j2 U5 Z
7 m. y" h* h: M C' n
template< class _T> std::string ToString( _T const&);2 r( G( @; f# B' ?0 L: u% @8 }( B
- a! F) D! q3 N; V
template< class _T, int _Check> struct __ToString_Category;2 m9 s5 P* |% M
template< class _T> struct __ToString_Category<_T, 0>{ // Single8 S& D9 K! H7 h4 i( Y r. ^
template< class _t> static std::string TOstring( _t const& _v){
% Y6 k- r, c4 ] W8 Y2 }% G4 `/ b std::ostringstream ANS; ANS.precision( std::cout.precision()); ANS.setf(std::cout.flags()); ANS<<_v;; w' _7 R5 X0 U& }+ B
return ANS.str();( A6 h2 o R4 q. S/ B, _
}
) ~# \9 {+ q6 A2 c/ W$ C' }4 r0 s static std::string TOstring( unsigned __int128 const& _v){ auto v = _v; std::string ANS; if(v==0){ ANS="0";} else{ for(;v!=0;v/=10){ ANS+=('0'+v%10);} std::reverse(ANS.begin(), ANS.end());} return ANS;} K/ F% q2 X+ b& o% Q8 z6 q) a
static std::string TOstring( __int128 const& _v){ std::string ANS; auto v = _v; if(v==0){ ANS="0";} else{ if(v<0){ ANS+="-"; v=-v;} for(;v!=0;v/=10){ ANS+=('0'+(v%10));} std::reverse(ANS.begin()+(ANS[0]=='-'?1:0), ANS.end());} return ANS;}
# x3 f7 L% Q: Y9 X+ g8 o) R static std::string TOstring( bool const& _b){ return (_b?"1":"0");}' a% a7 J* |8 \1 ^" D
static std::string TOstring( char const& _a){
/ [$ u6 k7 X5 r3 } M std::string ANS="'?'";
' O8 E1 D# m# j: j ANS.replace( 1, 1, std::to_string(_a));# H/ S# Z: |. c: t
return ANS;
7 F O5 P5 k5 `, f) {% f. e5 s }% E" p; k& m; W* K P2 P# F+ [ T
static std::string TOstring( char const* const& _s){ return TOstring(std::string(_s));}0 L( |! V1 W2 K" w- K; k6 ?' Z! @
static std::string TOstring( std::string const& _s){ std::string ANS="\""; ANS+=_s; ANS+='\"'; return ANS;}
w0 g' o( Y8 Q$ o9 O, z. ?- U };
# }$ ? b W: W; T( g( w/ a [ template< class _T> struct __ToString_Category<_T, 1>{ // Container6 K0 l. s6 k9 O' ^4 j& Y
template< class _t> static std::string TOstring( _t const& _v){
5 Z- l5 z3 p- k9 \( G6 Q std::string ANS="["; bool first=1; for( auto const& i : _v){ if( 0==first) ANS+=","; if( first) first=0; ANS+=ToString(i);} ANS+="]";, i/ [6 h3 T; [: v% }* n5 D5 ?6 ~
return ANS;- x: X2 T5 a: G8 `4 ], A b
}2 O) r+ Y$ d, F9 V
};/ Q$ w7 C3 N! Z7 N' l
template< class _T> struct __ToString_Category<_T, 2>{ // Pair( Y% X6 s/ F" a( Z( @9 U9 C
template< class _t> static std::string TOstring( _t const& _v){ std::string ANS="("; ANS += ToString(_v.first); ANS+=","; ANS+=ToString(_v.second); ANS+=")"; return ANS;}
/ p4 B8 ~# z& n& p };, _, @6 K3 m' E. ?" z1 _+ \: G
template< class _T> struct __ToString_Category<_T, 3>{ // Stack* M( M' \! G: t- D9 s9 } r7 Y2 H( O
template< class _t> static std::string TOstring( _t const& _v){ std::string ANS="Stack(top)["; auto t = _v; for( bool first=1; t.empty()==0; t.pop(), first=0){ if(first==0){ ANS+=",";} ANS += ToString(t.top());} ANS+="]"; return ANS;}: _1 p2 }5 P/ K A0 R ?
};6 S2 _4 a" _; b# ~5 r6 r% a! F, ^! A
template< class _T> struct __ToString_Category<_T, 4>{ // Queue
3 B! t4 _- t; v* n" G4 E0 V9 |6 o3 ? template< class _t> static std::string TOstring( _t const& _v){ std::string ANS="Queue(front)["; auto t = _v; for( bool first=1; t.empty()==0; t.pop(), first=0){ if(first==0){ ANS+=",";} ANS += ToString(t.front());} ANS+="]"; return ANS;}
* v+ d z4 ]" V };6 f$ O; Y6 g& e4 @+ W5 c
template< class _T> struct __ToString_Category<_T, 5>{ // Deque p( k/ M9 v: |: h T5 g
template< class _t> static std::string TOstring( _t const& _v){ std::string ANS="Deque(front)["; auto t = _v; for( bool first=1; t.empty()==0; t.pop_front(), first=0){ if(first==0){ ANS+=",";} ANS += ToString(t.front());} ANS+="]"; return ANS;}
, J1 f; ^. L) ~" c+ O };
+ b* n4 K+ H$ i. `* W; Z. {. _, s- u) a2 a4 X, q1 t2 T
template< class _t> struct __ToString : __ToString_Category<_t, (IsContainer<_t>::value ? 1:(IsPair<_t>::value ? 2:(IsStack<_t>::value ? 3:(IsQueue<_t>::value ? 4:(IsDeque<_t>::value ? 5:0)))))>{};
2 Z: _9 X, O* s4 m! w- [ `- B2 C7 J: g( P; z2 q$ W
template< class _t> std::string ToString( _t const& _v){ return __ToString<_t>::TOstring(_v);}% Y( w: O6 L8 M9 v( J2 W; o2 K1 d
4 R$ h' [( B1 G! [
template< class... _H_> std::string ToString_Items( _H_ const&...){ return "";}7 T3 j$ Q+ S" K# w: W9 S6 b
template< class _H_> std::string ToString_Items( _H_ const& _h){ return ToString(_h);}
7 D: r* U: P5 Z$ b template< class _H_, class... _T_> std::string ToString_Items( _H_ const& _h, _T_ const&... _t){ std::string ANS; ANS+=ToString( _h); ANS+=", "; ANS+=ToString_Items( _t...); return ANS;}5 E: m$ X- i9 y
}, i) ^9 |2 {- q/ i- w4 s
//} omipusDebug.hpp
/ E- Z$ K/ U* U U# e1' Y1 `& C. T3 T# t- p
21 P5 W* a- _* Z4 R4 V$ n
3
, h! z1 x a: s0 m+ P2 q, h; f4
7 w+ c) d8 L* ^0 m& W5 X. R* e1 G, a C2 o
6; s9 |+ R8 M7 F! B# F, J* A0 S5 S
7# ~* ^% Q5 K$ o5 j9 `5 ]* _9 F
8
& J6 ~2 e$ w( L92 S( Y/ N# _$ b1 J4 ?
10
# N: |& u) ?& x8 R2 A115 r. A$ a2 X+ S
121 w7 h! O ?+ r
13& r1 s' N: \+ W, Q' R7 j) D
14
; p% A6 C5 k4 v. P15 M3 |/ m# @& {$ ]8 m
16' z9 `/ Z9 C2 Z; K* b
178 J& ?- ? |/ Q5 w# O
182 m: U# j* Y# d- O, u7 d8 D
198 @& r1 a+ C/ }6 n' h
203 G1 X, C, A7 z! V8 @8 ]
21$ L; k4 k- v# _- P6 U$ N; p1 n
22 M6 _% Q* O) ?
231 ~- o+ ? W9 ^, S, d1 r5 N
24
4 x3 T2 Q$ ~0 e251 B3 K8 Q y6 e, D
26) r% ?& C$ G( `" b( I% F4 t5 l
27. c X, D O0 B/ e& `/ E) R
28# ]! s% X( u1 M* X
29' k5 P- v$ \# w+ M6 v8 W" p( Y/ C% \
30$ D% q% s! B" w9 u7 M8 Y
31/ H5 S" h% x: T3 n- W) Y& J
32
# Y3 o5 |( i" [- R9 [334 c, T/ {. U: M
34
( ^& j2 n' g4 d0 x35# R/ n% m8 t- r" [* x( y/ U3 Z
366 W+ F+ a" t3 H3 f/ }6 U# N
37# j9 K! F$ N- J7 w$ k
386 U; U# M7 {& U. n) t
39
8 f% D& V8 e! z7 D5 H40 {% H+ P2 R1 n. U% v5 f6 x d: \
41: T) f# f" ]4 ]* x4 }
42' y: L7 c3 _0 `$ X+ z
43
4 M- |) |' y8 e# V1 l" P, p0 M" a442 u2 L1 a: K, j( a5 }
455 c4 J( v, R9 v3 i+ n l/ K
46& K8 P- n' w" ]5 Q
47: N. s8 a6 h4 F' C& [
48# A! _! ?- o7 W
49
' W2 `8 f" k7 \4 n+ y3 Z50
/ e* Q) T: f# u: e513 K& O, R. U# O D" O& Z+ \
52$ X l ?+ y4 A% _( { f; b8 m
53) e7 I/ b' N+ l. ?
54& ? \2 Z9 h2 U4 L9 C
55$ e4 `/ B+ _- w: v
56/ M: l5 d" K2 i5 E* |$ _1 h, \$ K
57( B) Y8 j$ \+ z$ o3 k. F! e# f
58! B/ f1 ?, g' }8 ^
593 v- b! d. _8 y% e8 g4 ^, p
60 B. n3 I1 }! A9 J% ? o
61( |& v) ?+ ]* S* w$ B$ y2 Z* V
62+ n& \( q8 u- o+ W% D
631 p, y. K- D+ k
64* a ^0 O4 f# i
65
1 j% p8 }( M! K7 b/ }6 i9 z' I! j" W8 F66
4 M7 k. y+ W O( t67' t2 x; k' I" J" Y! C3 t$ ]
68, a' @( N0 E3 ^# g5 N* c# t, r' x
69" K* \+ ?/ q- @; o" p
70! O* \1 a9 L+ x: Z5 }
71
3 @) l0 x! J5 V5 d/ T8 _72/ `! S4 c* L' F4 L v4 J
73
5 p% c1 }/ `! h9 i b0 Z74
5 A1 `( s+ q4 _0 ~2 V$ F) @75
! [: f9 N! M% I# N( b7 W! l7 d76 j0 k2 S) G6 J: W; m8 ?+ `$ d2 S' H
77
3 U t, O3 t L& u, G8 i" @) V78* D, ^& |5 {& C5 U, o5 ?) \
79$ B8 e4 r3 W4 R0 T0 @
80
" ^# f, B, c" A9 C. v' v i4 @" L1 D817 J8 q$ M* H2 Z; F3 t7 a! D- N
82
) X, T8 u& W* {83& p" o) }* C4 H
84* Q* N* }5 w" i0 p2 T6 i u0 ]2 P
85
2 {" N6 O3 g8 N4 `8 |% f( H算法競賽配置
8 V. U' m5 r- A- J1 Z0 U& _QT_Creator. g! Z* [7 f2 |2 v% N7 d% ?$ a
創建一個控制臺應用, 然後在Pro文件裏 添加CONFIG += c++17 (原來是c++11 修改成17);8 X4 C" C3 U% K$ C @ s5 d- _
+ b- g F7 H$ z* \) S對拍文件, g7 ?* X, b; \3 J8 d6 A: j
`compare.cpp`
+ O% r8 [6 A" j$ ^( n- ]( Q) c! P3 T* K# {9 G6 J
int main(){
, r3 n1 Z* P" f3 S& a. R vector< const char *> Init{"build.bat generate_data",
1 Q8 g0 y$ u# z6 M$ y- m "build.bat supimo",1 f% f4 x6 r, J- U8 x* w* d
"build.bat correct"};
1 b: D3 u* m- c, ~* d for( auto order : Init){9 a# u$ i9 F) R9 q
auto errorCode = system( order);6 o, g) M1 m! S( d1 F0 [. d
if( errorCode != 0){ EXIT_( order, errorCode);}/ i4 Y1 ]7 B7 L: F. n
}# W6 o2 P0 Y( M7 k+ ~
4 U; M8 S! S+ q9 B; R. g while( true){
, c/ I! f% t5 W) R6 T static const char * Ords[] = {"generate_data.exe > data.in",
0 T/ D/ k9 ~) {7 a% t9 e; K, | l "supimo.exe < data.in > supimoOutput.txt",$ \# A2 t: Z# Z8 K+ `1 N( b& l+ ?. r
"correct.exe < data.in > correctOutput.txt",6 E6 @6 K6 K! a% B
"fc supimoOutput.txt correctOutput.txt"};% O! r* k2 C, o6 Y( N% N' q, Z. x
for( auto order : Ords){* ]4 K0 P& F* l; Y3 @2 v
auto errorCode = system( order);
$ r+ A! a {- t, \% W& r" r& N if( errorCode != 0){ EXIT_( order, errorCode);}
4 P0 o% O6 t/ B$ _, u }
6 U( j, N0 C5 R$ L" P cout<< "SUCC"<< endl;
% Z( w$ P3 W# s3 z! j }
+ `% P8 L" k; h/ P, s" b* t
" `2 b- H9 W% M" @5 ] return 0;
! X3 y2 `8 e+ v1 H- }5 s. ~}* g, `: t' b; G
1$ Z+ w: ] K- B0 N) P( m/ I
2/ j/ Y( {2 u* J* u. h7 e
3
( K, ~; w* N& Y" ^4
& R2 b* s+ q) `! w, s4 b5
! R+ E: `" \- t- i! n6& n9 E- l0 d. e/ Q
7
& W1 q5 T: p: {1 y8
& f/ e( q7 _5 n9 m. _6 h# O' ^* q, ^+ c2 O, _
10
I6 |& E$ u! ^$ y/ A11
3 w% o% X& ^ g0 l) e12
, P9 C! k* ^: i0 \1 k; S0 y13) e& U. Y9 p1 N
141 S$ c! b, W, m0 W5 A9 }
15: A0 D" a% ^8 Z1 H- C
16
$ y. b6 t$ m8 O2 a/ x9 B17
4 c( Z, U. s$ w6 |183 E* n: I" C6 d, f% u4 ?, ~# J
192 e5 ^. V0 |3 }/ O& R
20
* x0 |3 Z: C: A# ~) n21( p! _, j& {6 ^6 N& H
22' ?/ v3 ]' L2 V# M0 j2 l
233 f! K7 V: @; k9 X( p' d; g% x
24$ C1 h8 ^8 F& b, p3 `
25$ G( g& Z( v2 p: k5 ~- h
Bat代碼$ n: W" S4 V, }9 h+ X& _) |
build.bat+ w1 L4 Z( t/ j- x8 F) c. v: v
@echo off# w1 Q1 R) _, J
del %1.exe# f9 c7 O5 V6 N5 [
g++.exe %1.cpp -o %1.exe -std=c++17 -O2 -Wall -Wl,--stack=268435456 -D"__ISsupimoENVIR_"* s* I, @8 w/ y# c6 Q( _
/ P2 }; n# G. H: Y- \, }5 z@DELI;
, t" F: z+ \0 e/ X) q' h9 V" k" t6 S! ~
run.bat
G! i5 b6 @. i' k5 v@echo off( z- C9 S8 _6 }/ [
%1.exe < input.txt; Q: P5 _' r: B: B
) c0 F8 d- Z7 x% I& V5 S
@DELI;
" y( x1 z, l' E2 F: E% y1 f
, `3 S' E' s3 N- N' z& Fbuild_and_run.bat* _; h7 R" {7 c
@echo off( H* d0 z, G0 q, M8 W7 Y- G
call build.bat %1
) U \3 y& `, Y- J+ ^call run.bat %1 %2
" J& \0 q0 C. c- q1
0 M" n0 ?& ]9 ~6 l0 x4 l2 Z- f2
* N% C- g% Y! S, r3
# c7 g0 K# W0 ^' C2 O5 m2 f8 J48 w5 O, S# _' A4 u& H
5
' c, m# ?" m. b( z4 O4 ^63 E7 Z, t% i+ K; Y- @5 ~0 K" \
7! ]$ n7 n: @) r& I y
8$ y& \" r5 ?0 J5 y" O
9
" T4 O4 h% A. i7 t4 W10
) P& z) p& P+ s8 J- s s11" j$ J* J+ i% `3 P
127 J' o* [2 ?& ]6 i+ o4 Q4 h
13% c# P" d: y! r
14
5 d# n! t. k o, `2 a8 q15) y; C( _ D( g' t3 N! h! s
16
$ I$ R3 z6 J. o0 @, v# G1 D17" V- ]2 l; ^8 }2 L3 {: I
源文件" {% @ t8 s& `& k7 o& D
#include <bits/stdc++.h>
- v- w: W2 w9 K3 a/ ]5 X _using namespace ::std;
4 {+ H( k5 u& [) }1 x" A, o1 X( u5 s6 E& l
//{ ___SUPIMO
& G; `! S/ j6 o$ x) e3 dnamespace ___SUPIMO{+ O* r {; k0 T5 S8 w, g
//{ Macro
2 Q9 d. h' ^4 X' @8 B8 D8 @& M k#define ASSERT_CUSTOM_( _op, ...) if( !bool(_op)){ std::cout<<"Assertion_Failed(Custom):["<< #_op<< "], Hint:["<< ___SUPIMO::Debug_::__ToString_items( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< ")\n"; EXIT_;}
0 [& M5 k L& ?& g; v#define ASSERT_SYSTEM_( _op, ...) if( !bool(_op)){ std::cout<<"Assertion_Failed(System):["<< #_op<< "], Hint:["<< ___SUPIMO::Debug_::__ToString_items( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< ")\n"; EXIT_;}
7 s. z* B _1 f; D#define ASSERT_MSG_( _msg)
" T6 \' |( T* A; j$ I& N5 t6 G9 v#define TODO_RunTime_( _msg) ASSERT_SYSTEM_( 0, "@TODO: " _msg)5 ~& k; a: U! M& @# x- d$ J
#define EXIT_ std::cout<< "EXIT: Line("<< __LINE__<< ")"; std::exit(1);
) F& u; L; k; u) A' t; A#define EXIT_COUNTER_( _max) { static int cont = 0; ++ cont; if( cont == _max){ string str = "EXIT_COUNTER(" + to_string(_max) + ")"; DE_(_str); EXIT_;}}
/ q# Z! a' j# J7 o* ?2 r; e2 u0 e+ y#define FOR_( _i, _l, _r) for( int _i=int(_l); _i<=int(_r); ++_i)0 O4 A+ a9 C( t8 ]; n2 ?& u" }
#define FOR_R_( _i, _l, _r) for( int _i=int(_l); _i>=int(_r); --_i). F5 w1 c; R7 {8 H* m# b; I2 _+ A
#define DE_( ...) if( ___SUPIMO::Debug_::___IsInDebug){ std::cout<< ___SUPIMO::Debug_::__ToString_items( __VA_ARGS__)<< " {Line: "<< __LINE__<< ", Msg: ["<< #__VA_ARGS__<< "]}\n";}
: m0 r5 z9 h0 I7 ~#define NOTE_( _str)
& E$ _+ y6 E- L- k+ C3 B//} Macro8 ^. I) T: f+ l" [; \
+ w2 g# j1 a+ n0 ?3 Ynamespace Debug_{2 y. i0 B( }% p- S8 [; g) R: E
static constexpr bool ___IsInDebug = 1;
# v3 ~! G; o& X) L! p7 k template< class _T> string __ToString( const _T &); string __ToString( unsigned __int128); string __ToString( __int128); string __ToString( bool); string __ToString( char); string __ToString( const char *); string __ToString( const string &); template< class _T1, class _T2> string __ToString( const pair< _T1, _T2> &); template< class _T, int _N> string __ToString( const _T (&)[ _N]); template< class _T> string __ToString( const vector< _T> &); template< class _T> string __ToString( const set< _T> &); template< class _T> string __ToString( const unordered_set< _T> &); template< class _Key, class _Val> string __ToString( const map< _Key, _Val> &); template< class _Key, class _Val> string __ToString( const unordered_map< _Key, _Val> &); template< class _T> string __ToString( const multiset< _T> &); template< class _T> string __ToString( const unordered_multiset< _T> &); template< class _T1, class _T2> string __ToString( const tuple< _T1, _T2> &); template< class _T1, class _T2, class _T3> string __ToString( const tuple< _T1, _T2, _T3> &); template< class _T1, class _T2, class _T3, class _T4> string __ToString( const tuple< _T1, _T2, _T3, _T4> &); template< class _T1, class _T2, class _T3, class _T4, class _T5> string __ToString( const tuple< _T1, _T2, _T3, _T4, _T5> &);
4 D: o4 U g# A; p string __ToString_items(){ return "";} template< class _H, class... _T> string __ToString_items( const _H & _h, const _T & ... _t){ string ANS; ANS+=__ToString( _h); if( sizeof...( _t) > 0){ ANS+=", ";} ANS+=__ToString_items( _t...); return ANS;}: s* b$ S) v, T0 t
} // namespace Debug
9 c/ @, W7 ?. O/ X( u; G; n5 r w- r3 E8 o
//{ Type1 M( p# D) f/ j
template< class _T_> using Heap_small_ = std::priority_queue< _T_, std::vector<_T_>, std::greater<_T_> >;4 C( M- ]/ E- a0 z
. d z% H* a! k' }" t H& k2 ]$ `
struct Double{3 J* R5 b4 e3 r, H; k) @* ^
using __Type = long double; __Type Value; static constexpr __Type __epsilon = 1e-12;( ` |# P. d! {, S, L, B2 i
constexpr Double():Value(){} template< class _T_> constexpr Double( const _T_ & _a):Value(_a){} friend std::istream& operator>>( std::istream & _cin, Double & _a){ return _cin>> _a.Value;} friend std::ostream& operator<<( std::ostream & _cout, const Double & _a){ return _cout<< _a.Value;}
0 I9 g9 g2 m) n: r& N bool operator==( const Double & _b)const{ return (Value<_b.Value? _b.Value-Value : Value-_b.Value)<=__epsilon;} bool operator!=( const Double & _b)const{ return (0==(*this==_b));} bool operator<( const Double & _a)const{ if(*this==_a){return 0;} return Value<_a.Value;} bool operator<=( const Double & _a)const{ if(*this==_a){return 1;} return Value<_a.Value;} bool operator>( const Double & _a)const{ return !(*this<=_a);} bool operator>=( const Double & _a)const{ return !(*this<_a);}2 q& l* `2 e7 S: f4 G
Double operator-()const{ return -Value;} Double operator+( const Double & _b)const{ Double ANS = *this; ANS += _b; return ANS;} Double operator-( const Double & _b)const{ Double ANS = *this; ANS -= _b; return ANS;} Double operator*( const Double & _b)const{ Double ANS = *this; ANS *= _b; return ANS;} Double operator/( const Double & _b)const{ Double ANS = *this; ANS /= _b; return ANS;} void operator-=( const Double & _a){ Value-=_a.Value;} void operator+=( const Double & _a){ Value+=_a.Value;} void operator*=( const Double & _a){ Value*=_a.Value;} void operator/=( const Double & _a){ Value/=_a.Value;}
( p5 X5 ]: V4 V" g1 R# v/ X}; // class Double" V1 V d+ S( C# @$ {$ l% \
( V) u+ E( h4 O y! V
template< class _ModType_, __int128 _Mod> struct Modular{$ g9 K' U" C0 U7 k
ASSERT_MSG_( "_ModType_必须是{int/int64_t/__int128}");
8 S3 R4 }: l' D- ^/ B using __UnsignedModType_ = std::conditional_t< std::is_same_v<_ModType_,__int128>, unsigned __int128, std::make_unsigned_t<_ModType_> >;
8 ~4 a7 b1 K0 ]0 A inline static conditional_t< _ModType_(_Mod)<=0, __UnsignedModType_, std::add_const_t< __UnsignedModType_> > __Modular = _Mod; __UnsignedModType_ Value;
; t# E3 D$ D( x# R Modular():Value(0){} template<class _T> Modular( _T _v){ _v %= (_T)__Modular; if( _v<0){ _v+=__Modular;} Value = _v;}
% s1 f, D0 C9 y inline static void Set_mod( _ModType_ _mod){ static_assert( ! std::is_const_v<decltype(__Modular)>); ASSERT_SYSTEM_(_mod > 0); __Modular = _mod;}
. d+ {8 s! D# W3 | Modular operator-() const{ return Modular(0) - *this;} void operator++(){ ++Value; if(Value==__Modular){Value=0;}} void operator++(int){ ++Value; if(Value==__Modular){Value=0;}} void operator--(){ if(Value==0){Value=__Modular-1;} else{--Value;}} void operator--(int){ if(Value==0){Value=__Modular-1;} else{--Value;}} Modular operator+( const Modular & _b) const{ Modular ANS = *this; ANS += _b; return ANS;} Modular operator-( const Modular & _b) const{ Modular ANS = *this; ANS -= _b; return ANS;} Modular operator*( const Modular & _b) const{ Modular ANS = *this; ANS *= _b; return ANS;} Modular operator/( const Modular & _b) const{ Modular ANS = *this; ANS /= _b; return ANS;} bool operator==( const Modular & _b) const{ return Value == _b.Value;} bool operator!=( const Modular & _b) const{ return (0==(*this == _b));} bool operator<( const Modular & _a) const{ return Value < _a.Value;} bool operator<=( const Modular & _a) const{ return Value <= _a.Value;} friend ostream& operator<<( ostream & _cout, const Modular & _a){ return _cout<< "Modular("<< Debug_::__ToString(_a.Value)<< ")"; return _cout;} void operator-=( const Modular & _a){ if( Value < _a.Value){ Value = (__Modular - (_a.Value - Value));}else{ Value -= _a.Value;}} void operator+=( const Modular & _a){ Value += _a.Value; if( Value >= __Modular) Value -= __Modular;} void operator*=( const Modular & _a){ if( std::is_same_v<_ModType_,int> || std::is_same_v<_ModType_,int64_t>){ using __MultiplyType_ = std::conditional_t< is_same_v<int, _ModType_>, uint64_t, unsigned __int128>; Value = __MultiplyType_(Value) * _a.Value % __Modular;} else{ Modular ANS = 0; Modular a = *this; auto b = _a.Value; while( b != 0){ if( b & 1) ANS += a; a += a; b >>= 1;} *this = ANS;}} void operator/=( const Modular & _a){ ASSERT_MSG_( "`Mod`為質數"); ASSERT_SYSTEM_( _a.Value != 0); *this *= _a.Power( __Modular - 2);} template< class _T> Modular Power( _T _p) const{ Modular t = *this; Modular ANS(1); while(_p!=0){ if(_p&1) ANS*=t; _p>>=1; t*=t;} return ANS;}1 W9 e% ?# }2 {: `* B" J
}; // class Modular
( g2 m4 Z K X6 F$ Q) i* d* @" _: F//} Type
: I7 X" b% p7 t2 p+ g
* z6 j6 c. R% O( |$ e8 fnamespace Integer_{2 a2 t, u) T' w9 J
template< class _T_> _T_ Get_divideFloor( _T_ _a, _T_ _b){ ASSERT_SYSTEM_( _b != 0); _T_ ANS = _a / _b; if( _a%_b!=0 && ANS<=0){ if( ANS == 0){ if( (_a<0&&_b>0) || (_a>0&&_b<0)){ -- ANS;}} else{ -- ANS;}} return ANS;}( I- C# b' d4 k" s7 @
template< class _T_> _T_ Get_divideCeil( _T_ _a, _T_ _b){ ASSERT_SYSTEM_( _b != 0); _T_ ANS = _a / _b; if( _a%_b!=0 && ANS>=0){ if( ANS == 0){ if( (_a>0&&_b>0) || (_a<0&&_b<0)){ ++ ANS;}} else{ ++ ANS;}} return ANS;}
# @) }6 n+ ]9 O template< class _Type_> _Type_ GetPowerRoot( _Type_ _a, int _p){ NOTE_("a^(1/p)的下取整"); static_assert( std::is_integral_v<_Type_>); ASSERT_SYSTEM_(_a>=1 && _p>=1); _Type_ ANS = std::pow<Double::__Type>( _a, (Double(1)/_p).Value); while( 1){ auto t = ANS; for( int i=1; i<_p; ++i){ t *= ANS;} if(t>_a){ -- ANS;} else{ break;}} while( 1){ auto t = ANS+1; for( int i=1; i<_p; ++i){ t *= (ANS+1);} if(t>_a){ break; } else{ ++ANS;}} return ANS;}
& m1 q- W& R4 X; ^2 ?; Q4 U/ G template< class _TypeRadix_, class _TypeNum_> struct Radix{ // `TypeRadix: 每个进制的类型; TypeNum: 所能表示的最大十进制数的类型`;
& g* ?& r- {* L* ?* w3 s std::vector<_TypeRadix_> __Radix; // 比如`Radix=[2,4,3]`, 那么所有的数为`([0-2), [0-4), [0-3))` 即表示的十进制数范围为`[0, 2*4*3)`; (Radix累乘值的大小 就决定了`TypeNum`);( N. Q2 B/ ]1 A" Z" C2 E c1 h1 A! F
std::vector<_TypeNum_> __SuffixProduct; // `SuffixProduct[i] = Radix[i]*Radix[i+1]*...`; E: p4 }1 K L; o g, h
void Initialize( std::vector<_TypeRadix_> const& _radix){ __Radix = _radix; __SuffixProduct.resize(_radix.size()); __SuffixProduct.emplace_back(1); for( int i=int(_radix.size())-1; i>=0; --i){ __SuffixProduct[i]=__SuffixProduct[i+1]*_radix[i]; ASSERT_SYSTEM_(__SuffixProduct[i]/__Radix[i]==__SuffixProduct[i+1]);}}3 T' m' E" Y* q" H, P
_TypeNum_ VectorToInteger( vector<_TypeRadix_> const& _v){ NOTE_("`v.front()`是*高位*"); ASSERT_SYSTEM_( _v.size()==__Radix.size()); _TypeNum_ ANS = 0; for( int i=0; i<int(_v.size());++i){ ASSERT_SYSTEM_( _v[i]>=0 && _v[i]<__Radix[i]); ANS*=__Radix[i]; ANS+=_v[i];} return ANS;}+ y4 T- G& ^5 A& _
std::vector<_TypeRadix_> IntegerToVector( _TypeNum_ _a){ NOTE_("`返回值.front()`是*高位*;"); ASSERT_SYSTEM_( _a>=0 && _a<__SuffixProduct.front()); std::vector<int> ANS; for( auto it=__Radix.rbegin(); it!=__Radix.rend(); ++it){ ANS.emplace_back(_a % (*it)); _a/=(*it);} std::reverse(ANS.begin(), ANS.end()); return ANS;}5 p2 z. l/ ^/ W7 ?3 D I
int GetBit( _TypeNum_ _num, int _ind){ NOTE_("`ind==0`是最高位"); ASSERT_SYSTEM_( _ind>=0 && _ind<int(__Radix.size())); return _num / __SuffixProduct[_ind+1] % __Radix[_ind];}
' O" ~# \# T% o) H) ~2 R L! i void SetBit( _TypeNum_ & _num, int _ind, int _v){ NOTE_("`ind==0`是最高位"); ASSERT_SYSTEM_( _ind>=0 && _ind<int(__Radix.size()) && _v>=0 && _v<__Radix[_ind]); _num += (_v - GetBit(_num,_ind)) * __SuffixProduct[_ind+1];}
! _- @0 U% z" l! l: M };
. L: K# j; s" x9 J& Q6 v namespace Binary_{6 v2 }, f5 k6 n9 v, k4 d
template< class _T_> std::vector<int> GetBits( _T_ const& _a, int _len){ NOTE_("a的低len位, @IF(len=-1){a的全部位}"); if( _len == -1){ _len = 8*sizeof(_T_);} std::vector<int> ANS(_len); for( int i = 0; i < _len; ++i){ ANS[_len-i-1] = (_a>>i)&1;} return ANS;}
2 ~( _4 N! k# L2 v# A" U4 S+ o template< class _T_> _T_ Get_sufixOnes( int _len){ NOTE_("返回值形如[0...01...1] 末尾有`len`"); ASSERT_SYSTEM_( _len>=0 && _len<=8*(int)sizeof(_T_)); if( _len == 0){ return _T_(0);} using Tu_ = std::make_unsigned_t<_T_>; return (((Tu_(1)<<(_len-1))-1)<<1)|1;}7 \7 ~, B1 T5 L
template< class _T> void SetBit( _T & _num, int _ind, bool _v){ if( _v){ _num |= ((_T)1 << _ind);} else{ _num &= (~( (_T)1 << _ind));}}2 W( X/ b2 K8 S; ?
template< class _T_> void RemoveBit( _T_ & _a, int _ind, bool _v){ NOTE_("删除[ind]位 高位下移 且最高位补`v`"); ASSERT_SYSTEM_( _ind>=0 && _ind<8*(int)sizeof(_T_)); using Tu_ = std::make_unsigned_t<_T_>; _a = (_a&Get_sufixOnes<Tu_>(_ind)) | ((_a&(~Get_sufixOnes<Tu_>(_ind+1)))>>1); SetBit( _a, 8*sizeof(_T_)-1, _v);}2 J" T$ {5 `+ G
template< class _T_> int Get_lowBit( _T_); template<> int Get_lowBit<int>( int _a){ if( _a==0){ return -1;} return __builtin_ctz(_a);} template<> int Get_lowBit<int64_t>( int64_t _a){ if( _a==0){ return -1;} return __builtin_ctzll(_a);}
5 f7 t6 |( X4 u$ Q template< class _T_> int Get_higBit( _T_); template<> int Get_higBit<int>( int _a){ if( _a==0){ return -1;} return 31-__builtin_clz(_a);} template<> int Get_higBit<int64_t>( int64_t _a){ if( _a==0){ return -1;} return 63-__builtin_clzll(_a);}
( w# O; x! t* P Q4 u/ r template< class _T_> int Get_bitCount( _T_); template<> int Get_bitCount<int>( int _a){ return __builtin_popcount(_a);} template<> int Get_bitCount<int64_t>( int64_t _a){ return __builtin_popcountll(_a);}
1 E: c a ^: v% `4 D8 z // #枚举二进制子集#: `for( auto subST = st; ; subST=(subST-1)&st){ @MARK(0); if(subST==0){ break;}}`遍歷`st`中所有`1`的選/不選的方案; (比如`st=1101`, 則在`@MARK(0)`处你会得到`subST=[1101,1100,1001,1000,0101,0100,0001]` 一定*严格递减*);
& A! U' X, t( N& ^* e* y; M' g: B } // namespace Binary; Z& |1 b% P e( w8 ~1 w6 E0 L8 f
} // namespace Integer
1 A2 F! `3 R8 p- _; a+ J! f$ d" g$ H5 F% g7 i, e, t# r
namespace String_{
' W# E4 U# I ~) @& h void Replace( string & _cur, int _l, int _r, string const& _new){ ASSERT_SYSTEM_( _l>=0 && _l<=_r && _r<(int)_cur.size()); _cur.replace( _l, _r-_l+1, _new);}) y+ s6 y d1 g% f$ ]
void Replace( string & _cur, const string & _raw, const string & _new){ int m = _raw.size(); for( int i = 0; i < (int)_cur.size();){ if( i+m<=(int)_cur.size() && _cur.substr(i,m)==_raw){ _cur.replace( i, m, _new); i += _new.size(); continue;} ++ i;}}3 Z/ P! m) a+ f, z! \2 [' n' R
vector<string> Split( const string & _s, const string & _split){ vector<string> ANS; string cur; int n = _s.size(), m = _split.size(); for( int i = 0; i < n;){ if( i+m<=n && _s.substr(i,m)==_split){ if( cur.empty()==false){ ANS.push_back(cur);} cur.clear(); i += m; continue;} cur += _s[i]; ++ i;} if( cur.empty()==false){ ANS.push_back(cur);} return ANS;}
: G4 s0 y* S# n} // namespace String8 _. H* @( v9 g5 {' o3 o) d; c
0 F' W! ?9 j; q' D4 k& `1 anamespace Random_{
" y" t. ~7 O& N+ Z' u* r std::mt19937 MT32( std::chrono::steady_clock::now().time_since_epoch().count()); std::mt19937_64 MT64( std::chrono::steady_clock::now().time_since_epoch().count());' a) P/ i4 x$ o7 v) k9 t
int GetInt32( int _l, int _r){ return (int64_t)(MT32() % ((uint32_t)_r - _l + 1)) + _l;} int64_t GetInt64( int64_t _l, int64_t _r){ return (MT64() % ((uint64_t)_r - _l + 1)) + _l;} Double GetDouble32( Double _l, Double _r){ return _l + (_r - _l) * ((Double)MT32() / (Double)UINT32_MAX);} Double GetDouble64( Double _l, Double _r){ return _l + (_r - _l) * ((Double)MT64() / (Double)UINT64_MAX);}
3 o7 S" u5 ]+ l" p: ?} // namespace Random6 @8 r+ g% X( H
/ H( F7 O/ p; \! t; m% w& p0 Enamespace Object_{
; X! c; z! A- i8 F const Double Pi = std::acos((long double)-1);
9 E; k( V5 N* q template< class _T_> struct __Int_0x80; template<> struct __Int_0x80<int8_t>{ static constexpr int8_t Data = 0x80;}; template<> struct __Int_0x80<int16_t>{ static constexpr int16_t Data = 0x8080;}; template<> struct __Int_0x80<int32_t>{ static constexpr int32_t Data = 0x80808080;}; template<> struct __Int_0x80<int64_t>{ static constexpr int64_t Data = 0x8080808080808080;};
) S( K: X* _- R7 K7 B1 | template< class _T_> constexpr std::decay_t<_T_> Int_0x80 = __Int_0x80<std::decay_t<_T_> >::Data;
) _/ x6 c7 ], a& M; `# j4 O template< class _T_> struct __Int_0x7F; template<> struct __Int_0x7F<int8_t>{ static constexpr int8_t Data = 0x7F;}; template<> struct __Int_0x7F<int16_t>{ static constexpr int16_t Data = 0x7F7F;}; template<> struct __Int_0x7F<int32_t>{ static constexpr int32_t Data = 0x7F7F7F7F;}; template<> struct __Int_0x7F<int64_t>{ static constexpr int64_t Data = 0x7F7F7F7F7F7F7F7F;};* b& C" o' Y" A$ U+ ]$ ^9 N
template< class _T_> constexpr std::decay_t<_T_> Int_0x7F = __Int_0x7F<std::decay_t<_T_> >::Data;1 c5 P# Q: C) M C
} // namespace Object
# I' N- i5 p6 ^$ Y2 ]: n4 E" E1 g) a
namespace Function_{3 I* |9 |, N+ @* P- y3 H' f0 a
std::clock_t ClockSplit(){ static std::clock_t __ANSTime = -1; if(__ANSTime != -1){ auto pre = __ANSTime; __ANSTime=std::clock(); return std::clock()-pre;} __ANSTime = std::clock(); return 0;}0 c* W; v( D4 h) ]) S
template< class _T> _T Get_GCD( _T _a, _T _b){ ASSERT_SYSTEM_( _a!=0 || _b!=0); while( _b != 0){ _a %= _b; std::swap( _a, _b);} return std::abs(_a);}
; I0 Z8 p! B6 n) |/ C3 v template< class _T> bool IsInInterval( _T _c, _T _l, _T _r){ return (_c>=_l && _c<=_r);}5 A/ y7 h" y6 V9 E8 z% K
template< class _T_> bool IsInSegment( const pair<_T_,_T_> & _c, const pair<_T_,_T_> & _p1, const pair<_T_,_T_> & _p2){ static_assert( std::is_integral_v<_T_>); bool ANS = 0; if( _p1.first==_p2.first){ if( _c.first==_p1.first && _c.second>=std::min(_p1.second,_p2.second) && _c.second<=std::max(_p1.second,_p2.second)){ ANS = 1;}} else if( _p1.second==_p2.second){ if( _c.second==_p1.second && _c.first>=std::min(_p1.first,_p2.first) && _c.first<=std::max(_p1.first,_p2.first)){ ANS = 1;}} else{ auto gcd = ___SUPIMO::Function_::Get_GCD( _p2.first-_p1.first, _p2.second-_p1.second); auto dx = (_p2.first-_p1.first)/gcd, dy = (_p2.second-_p1.second)/gcd; auto cx = (_p2.first-_p1.first)/dx, cy = (_p2.second-_p1.second)/dy; auto dx1 = _c.first - _p1.first, dy1 = _c.second - _p1.second; if( (dx1%dx==0) && (dx1/dx>=0) && (dx1/dx<=cx) && (dy1%dy==0) && (dx1/dx==dy1/dy) && (dy1/dy>=0) && (dy1/dy<=cy)){ ANS = 1;}} return ANS;}
2 h6 F( f8 I) I6 W2 S9 H5 J} // namespace Function
# e9 f& v' S1 W5 |% ]7 W4 A' ~ h: b6 @
} // namespace ___SUPIMO5 r# p" Q1 g9 H3 U L
|: t$ W. Y7 A8 enamespace std {' n8 E7 ]( F$ T* m
template<> struct numeric_limits<___SUPIMO::Double> : public numeric_limits<___SUPIMO::Double::__Type>{};% d0 a8 N: c3 H" o2 R' D/ a
template<> struct __is_floating_point_helper<___SUPIMO::Double> : public true_type{};6 f5 q4 k9 k2 s8 L L3 y% J# A
template<> struct make_unsigned<__int128>{ using type = unsigned __int128;};9 `2 f- {, e/ m4 N1 @' ^% Z
___SUPIMO::Double abs( ___SUPIMO::Double const& _d){ return (_d>=0 ? _d:-_d);}% B H' t& k, t; S2 B
}
* V4 d1 A$ a' G2 S# @: U//} ___SUPIMO8 G( e: Q( P3 M) i; b) h9 u# K: y
% o) M% r8 y( R/ D! c. rusing namespace ::___SUPIMO;
7 S+ \0 Q' c* g1 ?) W8 d5 U0 ~* T+ _3 G# V) |2 u
void ___Solve_oneTest(){
. ?& B% B$ Q9 p; `! _4 k. B% ^2 J. ]" y+ o6 K! A
}7 l% _/ Y7 Q$ v5 m7 c% o
int main(){
. H- V U6 v1 a std::ios::sync_with_stdio(0); std::cin.tie(0); std::cout.setf( std::ios::fixed); std::cout.precision( 9);
2 j- l" T' _0 G$ M) l) O( M) O- @0 j. U. H: [
auto ___Work = [](){ // 必须严格与*题目*的录入格式对应;
3 `/ }" z. M% [4 y constexpr int8_t mode = 0;
+ l. }5 ]$ K4 g% b, F7 X int testsCount;+ ^$ k* [6 Y! v) u% N# I$ n V- [
if( mode == 0){ testsCount = 1;} else if( mode == 1){ cin>> testsCount;} else if( mode == 2){ testsCount = 1e9;} R+ ]4 X& d2 k) G7 c
for( int id = 0; id < testsCount; ++id){
8 N0 Q( H5 v& b# H9 I9 N, t6 M$ P if( id == 0){ // Global_Initialize" m; |5 m+ A% f
% n: b' g0 n; I. t; ~ }
) _, q( a- @: T7 i0 @8 a ___Solve_oneTest();
. L% D: g' |1 w* c6 |6 p. e( e }
2 E; L0 L! o, T2 k& o6 } };
7 _# {4 p) K. v if( ___SUPIMO::Debug_::___IsInDebug){
9 v" [: `& q9 i" G for( int id = 0; id < 100000008; ++id){
9 A7 n7 Q4 L. m, H& O: _% \! H0 u string flag; cin>> flag; if( flag == "___INPUT_-1"){ break;} ASSERT_SYSTEM_( flag == (string("___INPUT_")+char('0'+id)), flag);
, c# G6 L% \+ r& @; N+ d ___SUPIMO::Function_::ClockSplit();
- x7 c0 r% _4 \6 B- b1 l) q. s* L std::cout<< flag<< ":\n";
. }9 D, I+ c/ D/ Y6 m3 R ___Work();# c2 |. K @, Q" b; e6 j$ T8 m
std::cout<< "\nTimeElapsed: "<< ___SUPIMO::Function_::ClockSplit()<< "\n\n";
7 D3 p5 W4 t1 ?$ o% ]6 } }" Y, _1 L: T1 w( n, D% E& J @
}
7 R; W2 U# X m! M' r4 J0 o else{ ___Work();}
! I$ W: m/ ^8 \9 N6 ]$ h j% r9 D
; t( E8 x! W6 c+ ? return 0;
# W) {7 e9 R+ _5 X, ~& L5 C} // main
0 x- D# }9 a+ @& H
+ [: \) m& G4 y. d7 [namespace ___SUPIMO {
0 B2 Z2 R, z6 H1 z- N9 k' N1 e1 q" b namespace Debug_ {
* ?3 c6 a0 K( n, ^ template< class _T> string __ToString( _T const& _v){ ostringstream ANS; ANS.precision(cout.precision()); ANS.setf(cout.flags()); ANS<<_v; return ANS.str();}
- ^' p a: C& v% i! F" _( f string __ToString( unsigned __int128 _v){ string ANS; if(_v==0){ ANS="0";} else{ for(;_v!=0;_v/=10){ ANS+=('0'+_v%10);} reverse(ANS.begin(), ANS.end());} return "UInt128("+ANS+")";}
/ ?9 F6 Z- R4 f) O3 j. K1 m; y string __ToString( __int128 _v){ string ANS; if(_v==0){ ANS="0";} else{ if(_v<0){ ANS+="-"; _v=-_v;} for(;_v!=0;_v/=10){ ANS+=('0'+(_v%10));} reverse(ANS.begin()+(ANS[0]=='-'?1:0), ANS.end());} return "Int128("+ANS+")";}; U* m3 j9 q! L2 h" E) E6 f! e
string __ToString( bool _b){ return (_b?"true":"false");}6 f, Z8 Z; q& e
string __ToString( char _t){ string ANS="'?'"; ANS[1]=_t; return ANS;}! a5 O# x3 ]- a3 d8 _
string __ToString( char const* _s){ return string(_s);}
* g6 D$ |7 N. d3 y: V7 a4 W, L string __ToString( string const& _t){ string ANS="\""; ANS+=_t; ANS+='\"'; return ANS;}6 k* U C. I* S# W" C9 V
template< class _T, int _N> string __ToString( const _T (& _v)[ _N]){ string ANS; ANS+="Array["; bool first=1; for(int ind=0; ind<_N; ++ind){ if( 0==first){ ANS+=",";} else{ first=0;} ANS+=__ToString(_v[ind]);} ANS+="]"; return ANS;}" J5 y+ q0 E& @& _& k
template< class _T1, class _T2> string __ToString( const pair< _T1, _T2> & _v){ string ANS; ANS+="Pair("; ANS+=__ToString( _v.first); ANS+=","; ANS+=__ToString( _v.second); ANS+=")"; return ANS;}" h( K) m* `" o, A3 F, X
template< class _T> string __ToString( const vector< _T> & _v){ string ANS; ANS+="Vector["; bool first=1; for( const auto & i : _v){ if( 0==first) ANS+=","; if( first) first=0; ANS+=__ToString(i);} ANS+="]"; return ANS;}
* O" c2 p3 O9 f: P- o3 t% t# Q template< class _T> string __ToString( const set< _T> & _v){ string ANS; ANS+="Set["; bool first=1; for( const auto & i : _v){ if( 0==first) ANS+=","; if( first) first=0; ANS+=__ToString(i);} ANS+="]"; return ANS;}
! d! J/ q# u$ B template< class _T> string __ToString( const unordered_set< _T> & _v){ string ANS; ANS+="UnorderedSet{"; bool first=1; for( const auto & i : _v){ if( 0==first) ANS+=","; if( first) first=0; ANS+=__ToString(i);} ANS+="}"; return ANS;}# e' Y5 I7 S$ R1 ]
template< class _Key, class _Val> string __ToString( const map< _Key, _Val> & _v){ string ANS; ANS+="Map["; bool first=1; for( const auto & i : _v){ if( 0==first) ANS+=","; if( first) first=0; ANS+="("; ANS+=__ToString( i.first); ANS+=":"; ANS+=__ToString(i.second); ANS+=")";} ANS+="]"; return ANS;}, {1 Q6 Y, o4 o, ?
template< class _Key, class _Val> string __ToString( const unordered_map< _Key, _Val> & _v){ string ANS; ANS+="UnorderedMap{"; bool first=1; for( const auto & i : _v){ if( 0==first) ANS+=","; if( first) first=0; ANS+="("; ANS+=__ToString( i.first); ANS+=":"; ANS+=__ToString(i.second); ANS+=")";} ANS+="}"; return ANS;}* Y& s# [" B: E0 W5 \1 q
template< class _T> string __ToString( const multiset< _T> & _v){ string ANS; ANS+="MultiSet["; bool first=1; for( const auto & i : _v){ if( 0==first) ANS+=","; if( first) first=0; ANS+=__ToString(i);} ANS+="]"; return ANS;}% d# h: `% M; z P: Z
template< class _T> string __ToString( const unordered_multiset< _T> & _v){ string ANS; ANS+="UnorderedMultiSet{"; bool first=1; for( const auto & i : _v){ if( 0==first) ANS+=","; if( first) first=0; ANS+=__ToString(i);} ANS+="}"; return ANS;}
) s- ^4 H0 b& J+ ?5 Y2 g template< class _T1, class _T2> string __ToString( const tuple< _T1, _T2> & _v){ string ANS; ANS+="Tuple2("; ANS+=__ToString(std::get<0>(_v)); ANS+=","; ANS+=__ToString(std::get<1>(_v)); ANS+=")"; return ANS;}# E! V9 E% @" M
template< class _T1, class _T2, class _T3> string __ToString( const tuple< _T1, _T2, _T3> & _v){ string ANS; ANS+="Tuple3("; ANS+=__ToString(std::get<0>(_v)); ANS+=","; ANS+=__ToString( std::get<1>(_v)); ANS+=","; ANS+=__ToString(std::get<2>(_v)); ANS+=")"; return ANS;}7 Y& w1 X( ?: q$ _4 ~0 G t/ ~' [
template< class _T1, class _T2, class _T3, class _T4> string __ToString( const tuple< _T1, _T2, _T3, _T4> & _v){ string ANS; ANS+="Tuple4("; ANS+=__ToString(std::get<0>(_v)); ANS+=","; ANS+=__ToString(std::get<1>(_v)); ANS+=","; ANS+=__ToString(std::get<2>(_v)); ANS+=","; ANS+=__ToString(std::get<3>(_v)); ANS+=")"; return ANS;}' O# V$ X1 i7 b; U# ~! Z
template< class _T1, class _T2, class _T3, class _T4, class _T5> string __ToString( const tuple< _T1, _T2, _T3, _T4, _T5> & _v){ string ANS; ANS+="Tuple5("; ANS+=__ToString(std::get<0>(_v)); ANS+=","; ANS+=__ToString(std::get<1>(_v)); ANS+=","; ANS+=__ToString(std::get<2>(_v)); ANS+=","; ANS+=__ToString(std::get<3>(_v)); ANS+=","; ANS+=__ToString(std::get<4>(_v)); ANS+=")"; return ANS;}
8 T' C3 @+ B9 c- d3 {0 x5 j }6 N6 d+ H7 V$ ~
}# x# R) Z, [2 B F! y) B. Z5 ?% ]
1
9 p6 b8 \2 _3 M0 q. `2 Y2 Y2+ u" }$ r3 J- h+ M1 H4 L k
3' E$ c z) B P2 j# q( U4 [
4. k: T) X( ]* S0 O" M. ^6 y
5
6 A$ @5 g$ p) i Q+ v# X* \- i6! ~/ E: K* J* o8 R2 \2 j9 e6 |
7
, T* y: y% U) c8& V8 \4 i4 L+ T, s& \
9
9 b/ h$ n4 x5 j2 m, T8 G( L10
9 ]0 J& `# C" ~$ M; h# `11' r5 Y( a4 x3 N- M$ u6 e% y. N
12
: z7 M: L$ w' C) E: Q. x0 O139 b! S& U6 p3 }8 L6 D
147 s; ~( a7 v; {1 h4 N
15 M" }& u2 A* z% t! Y# B, N) w
16
, Z5 G6 D7 n0 e( ~0 i17! o5 u( {/ g- U* @+ Q
18- ?/ \& \7 V% G! \$ h0 a8 k
19
$ E" i' B/ a- r. \1 V. k+ ^20
: K* u; g/ T: S7 j1 }, P21
3 m1 |8 a# d! J22
6 i; M9 e! l/ ?5 Q4 k- o8 n23( o* {# R$ @9 ~% c3 m
24+ x) G T" s) h- H) Y
25
) F V" }8 k1 t' g# H26
' M- F5 E1 }3 I# j$ L27
l x1 M. P& q28 G; j3 H7 T: J s- z
29$ h4 {+ t" Z! Z
30
" Y/ v1 } J6 m313 j0 s: Y5 N( `' ^# C
32
/ k; W* ?7 ^; t; Q8 A2 w336 p: X! W& j: r- T; p
344 }; B& g& O( ~1 ]1 x
35& V$ ~5 r ^! u
36' W& ?0 W9 ~' ~0 I) J( `% }/ y
37% u" k1 h6 Z" }* b* @: D
38
4 W3 @9 t% w4 }6 n+ I! P( v, `) K39! e$ ?% ~/ z% d
407 @" x% w) u8 C4 S/ w% r" U! j w
41
5 V* P3 ~9 W4 o5 l% d+ y7 ^0 Z42: x- a5 a8 [+ z' K, t
43+ P% ^ x* c, u
44
: P1 j- H" e/ k+ U/ k0 q- x45
' s& k0 T+ h6 r462 \1 i/ x% @7 _$ I
47
- J- c& \6 a v( c' `3 U487 v" W. o& ^2 i, m1 a; [
49
; c# O1 A: v: n( M A50
/ X |# u- f' U( k9 s: G51; f! E: Y8 d/ P( o+ V
522 @, r+ W$ A' a2 c( G# K$ _+ {
53! q' q0 B9 W3 {- g" F0 y) p$ ]) _
54
* N+ x. ~' z! d. s55: N' i j4 [4 N
56" o E' v& n. m9 @
57$ ~' F/ {2 d) p
58, m7 n4 o+ x7 y& C
591 O }* n, n9 ^' ~
608 m. x5 G$ Q, v1 Y1 Z. C2 ~+ s
612 Y" {2 m+ b/ ]1 G& O& j9 D+ G2 I
62
9 j- }- B( I( r& [63
4 ~/ P; A7 Y4 H645 c0 s9 V, Y4 `8 J7 e2 r% ~
65
# W8 J/ f# t+ @- R66
% X3 @% y. e* ?67
7 n, q+ `, \9 L7 I68
: T/ `- c1 |& T7 m2 r69
3 W5 o4 n5 A! [( R70
- a: w" l( [6 ?' K5 {! z71
( ~/ b3 \9 a4 j0 T4 V6 F, F7 F" [72
2 W$ o% x& `. a5 t/ o73
I, @, G( U% h3 U" T* S# z. C74) e8 P6 o' R6 \: Y! v% ^4 X
751 U& r# E# h$ H+ s! A, i, y$ |
76+ z) Z$ V u7 x. a6 J
77
9 J7 C1 H6 @' `) T+ h78
+ k4 z" x; w, F1 K, h9 H! j' | ]: q79
6 k& ?. m4 d. Y) W808 ]$ b* C: U: M. Y
81
: M6 w! h% n7 x82# o( Q/ Z9 @; N- Q" ?+ ~8 Z
83
( ?6 s6 \1 E# a2 }, l84+ M. s+ d( B: Y/ \, P2 O
854 x; y7 t4 Z- e- K3 H* Q: T
86
/ c# ~4 l" V& u7 K87 z$ S1 Y& [( A$ J% o9 U) w
88
' a8 G) j/ T/ f9 P. l! i0 f. [3 f89, l1 j( F' x! c* o7 G
90
: S. z" U6 Z7 N# e# d6 k/ q; }+ v917 I! M+ S; `, d9 s+ v) d; Q( K
92
' N, H8 H' Q- [: j# m6 l" s93. [2 E* V; v; X3 X; h
94
A) w5 L7 _6 H7 M; r& V954 @( h, C& }, V
96
! _' \3 F+ K" w& m97
0 S9 C5 T# k% Q5 {8 ]98
) T; t1 \' Y6 X8 X ~3 ? R, I E99
+ O8 }6 G, m- E9 P: b6 J; g1 @9 y100
7 S: }! R; ]. A0 h9 Y5 y/ i101% P2 @! Z+ J& d; m; s
102
! s3 Z6 n+ h' h$ a8 q8 P103
1 i- t- T1 ^* E# S104
; V" U/ d$ H# b105+ q) \: l/ ]+ v2 Q
1062 f9 b$ d4 B4 N! r z, q$ v) a* v
1071 H. g6 f. F% ]4 ]
108
! G) U( L I; B" M) B& \- @9 I109& d* m. E0 ~& y1 }5 I& t
110. O" F) V W# ]6 e# w
111
7 S, C" P2 t3 u0 T( j3 f- C2 Y( e112, }& @5 y) I& t8 t
1131 U8 m# w. @ Y( F1 o
114
% a% F4 T. b9 h7 N- g1 f6 C115
- }4 `) L, Z F; c9 q6 F116
1 \( a' v3 ]' I- {6 P1174 l [* R/ L3 H: ]2 n, x
118
& S, q2 d5 B" v/ \; i) M; W. u3 o1190 a6 l i* e. q6 J$ W
120
; h$ d/ ~: p3 A4 T121
0 c; v4 I; x% |" l* }1229 I1 ^: t$ ^# R# {" V3 [' D
1235 R: g- s9 }2 h, v
124
& p" C. m% O8 l, |$ \5 I125! }+ F) M8 Q4 r$ T V
126! j& Y* T/ s1 ~' t0 a
127
2 }( t$ w, F* f8 x$ E) |/ S128, ^/ _, n% H9 b; i
129( U2 Y3 P+ Y& d/ \- j- }$ }* e8 O
130
* h- Q( h7 m u" A0 b+ z; r5 p131" e/ @5 ~8 r. u& ^" {
1326 i/ _- {+ f9 }8 l$ W* f C
133( L- L6 V8 z. j% b* ?
134
* b8 c6 V" u7 a1 Q0 r% v1350 }. o$ L1 V1 d
136
P3 ?9 C/ x4 |5 V3 Y6 `4 p2 m137
) M* `. |. M# U8 G138- J5 h) R6 r* `8 i
1390 E5 T6 \ _8 W( K( c: T2 `
1402 q! S- W4 G5 b3 H8 F
141
& C; P; M; B5 u! J142
& q: r& q- q* ]( F0 _6 O143* K) s4 U! I& l
144
, N) X% s7 }9 n4 u145# c, v. O: @/ g1 @! w- \
146
- _) h% h6 S% l# k; R5 g9 ^147 q' q X$ F) X/ {% W
148
" j" }7 p& @* {$ W9 ?' F. ~149
. [ Q; x6 Q9 @( p1506 m% b9 D0 x, r g
151
2 ]9 w; _" _" \2 ?6 J% T152
0 c% F* F. Y4 m2 }( J1 g153, E% M. ^# {# a7 o' x4 X
154
6 g$ K8 G$ w7 V3 X1 a1 T7 ~155% j9 b. v1 A8 E7 I" i% f7 F6 p
156
g0 J' ^* f! _, W157
6 w/ ^& s3 U% B2 H/ l1585 N4 Z" G2 E0 w) S# [
1591 O3 _) h+ p& P4 Z- J
160
# N4 D U8 _0 b5 ]0 G161& F' H, A/ \8 n! |; I3 @+ d
162
+ i4 R' ~- s# B* Q6 R; b o( e之所以把___Solve_oneTest()單獨寫成一個函數 而是放到main函數的for循環裡面, 因為: 當我們要進行特判 比如if( N==0){ cout<<"YES"; return;} 這裡的return 就是結束當前測試, 可是 如果你放到for循環裡面 你可能認為 那用continue不就可以了? 錯誤, 因為如果你內部還有for循環 這就出錯了 即此時continue不是對*外部的for循環*生效; 所以 必須要寫成函數形式;
+ W. F& o7 _ ~4 U
4 J1 Q r/ |3 O/ M; |Global_Initialize
* X, H) Z1 r6 g- |4 k. W0 s专为力扣设计的, 即全局(多组测试数据所共用的)数据的初始化;1 o1 L% z3 K2 b0 B+ S4 t: b" N
* r7 R. l' K1 s! lString, I/ ?$ Y7 r5 ?! t9 O. ~( }
Split的答案 一定不会有空字符串;
N7 L2 V% D9 d: }/ v, x' n他是从前往后贪心进行的, 比如"xxx" 以xx分隔, 那就是[xx] x 即答案是最后的那个x; 比如"xxxx" 以xx分隔 那就是[xx] [xx] 即答案是空的;7 ^0 j' a! S" m# _6 P
* M. F0 e/ U4 M: t F w@DELI;
" n) B- T2 g7 ]7 O7 [
# Y V8 V6 o; u% t" t+ [4 w1 qReplace的本质 就是Split函数, 即比如你Split得到的是? X ? X ? (将X替换为Y) 则答案就是? Y ? Y ?;
/ P! k# n1 H: q3 W9 \, ]. 比如S="xxxx", raw="xx", new="x", 那么答案是xx, 即先是[x] xx 然后[x] [x]; (并不是[x] xx 然后[x] x 然后x);7 h4 G0 \9 p+ Q, o/ ?! }0 {
; n; B. D) G! J. }" B8 i& p( V3 mDebug
4 P' ]. u* e3 e4 \" G1 Vif( ?){ Debug::__IsOpenedDebug = 1;} 和 Debug::__IsOpenedDebug = (?); 这两个 是不同的!# M/ ^# S" U: k" x0 o' p
前者: 他是在特定情况下 打开调试, 但是他不会关闭调试; 而后者: 他要么会打开调试 要么就关闭;% ^6 h( }6 i& W6 B! A
前者 通常用于 针对某个子流程而调试, 比如... [T] ... 最开始我们关闭调试, 然后到[T].入口时 打开调试, 然后到[T].出口时 关闭调试; 即整个过程 我们就调用了三次IsOpen = ?命令; 这通常在DFS时 使用的较多, 即符合某种条件时 进入某个DFS分支时 打开, 然后回溯回来时 关闭;
* z z; C, j! a4 |9 w. M而后者这种方式(即不停的根据条件 打开/关闭调试), 一般在非DFS的场景(比如FOR循环)里 会使用, 比如只对所有奇数进行调试;
" i6 A ]+ W' l) r即前者 他是针对一个连续的子段, 而后者是针对一个序列里 满足某条件的若干元素;' D/ R4 d l- Q2 f G, W
' Y7 |. y' b. d0 I" h/ m# g@DELI;1 F- L0 Q- e& `0 a1 j
$ h, h5 y: {% ^$ v9 g有個疑問: 為什麼要把他轉換成string 而不是直接cout輸出呢?. R" T# ~% V/ @" U
. 可能是多了一层封装? (但毕竟你这个模块 就只复杂Debug输出啊 有必要再多封装一层吗?
, C. ^! @' Q X8 e( H# J1 ]* K$ k* n9 D ~4 X
@DELI;& R+ A0 E% g( y7 Q0 R6 F
- h$ b; K( O( s6 S% n# P
INFO_里, 不可以对#__VA_ARGS__直接用,逗号分隔, 因为他可能是INFO_( F(a,b), 3), 所以你还得判断括号;7 d; x$ ~: u5 r
c9 E* h! v% Q7 g8 V) ~# i2 f
@DELI;3 Y; i) |( a5 z4 C* _) O0 Z: P
3 ~+ M' y; w& ?
T A[10];數組類型, 你可以直接輸出DE_(A);
) m2 B: Q; w- g& GDE_( (T(&)[5])A); 這是輸出A[0,1,2,3,4];
! z, X+ y) W+ H) s5 Q6 q# B" {* Z7 Q: q, r# F: @. f. L' U: x Q- T
auto A = new T[2][3] (此時auto == T(*)[3]);
. p; S1 s) U, l5 |# t" U. 要輸出他的所有元素, 此時直接DE_(A)是錯誤的(他是個指針地址), 正確語法是DE_( (T(&)[2][3])*A), 注意 *A的類型是T(&)[3], 但你把他強轉給T(&)[2][3]是可以的;
( l, w ]* U+ G9 [% l1 n3 W0 F. I1 J) S5 s7 a* }
@DELI;
5 s g8 e! u& n% b
1 R" Q Z( d. U2 \' p* }- f__Debug_list的參數 必須是const _H & _h, const _T & ... _t引用 不能是值傳遞;4 `% K8 L( ^. E! B
比如對於對象很大的情況(圖 本身都已經1e6級別的大小), 那麼 這已經不僅僅是效率問題了, 因為參數用的是棧空間 這是會爆棧的;$ ^0 y7 v# ]: z9 M; F7 q9 h2 D
" z6 P+ W# X1 n# `' @
@DELI;. i$ j, S: y3 b: k0 n3 A
" i* Y: r( x1 C* w/ x7 L( A! S
我们使用__Cout自己的重载函数 而不是去重载operator<<, 一个原因是 对于char/string基本类型的重载 此时和系统的就冲突了 (你需要再单独写个函数使用is_same去特判) 所以 不如就不使用系统重载符了 直接自己定义函数; 第二个原因是 其实把 两者本质都一样 我们自己写个__Cout函数 等于多了一层封装;% f/ O2 h# D; D- [7 X5 x9 f, P
8 [7 `. c+ c4 z! U# M; T' b) _你必须要声明/定义分开 這是為了實現對嵌套的輸出, 比如对于vector< map<int,int> >的输出 他使用了Cout( map<int,int>) 因此 你必须要有其声明在vector實現函數的前面;
3 U: |) G. v! V* F' d0 d: I
1 T. V3 ?& @& H9 p+ G- P( |+ ^如果是自定义类型 他会进入到Cout( T) 然后调用cout<< T, 即你的自定义类型 需要有重载运算符;$ R3 @1 q! @3 x+ u# x7 k
$ b7 t: R# r' b@DELI;
1 H% D: Z) ` w2 |: k( N- `+ d! T0 o3 ~% q9 j" w9 h* R; z
__Cout你不需要寫成 像ostream& operator<<( ostream&, T)那樣, 直接寫成void __Cout( T)即可, 這是因為: operator<<之所以要那樣寫 他是要實現cout<<a<<b<<...這個操作; 而__Cout 不會調用__Cout(a) << b這種操作;
: u6 q4 _: V, S1 y, ~8 ?# A( W$ r+ w7 \2 Q1 q8 Q
ASSERT報警宏( I! l+ d3 N& p
#如何关闭某个子模块的ASSERT$
9 D9 \7 C: ]( u+ t1 i# m对于算法模板A, 他里面有很多ASSERT_SYSTEM, 为了优化效率 如何把他们给关闭掉呢?
- }3 K' X- j \, u8 n2 N5 q$ n" f8 n' {6 v0 v+ h k
#undef ASSERT_SYSTEM_
$ s, H( a2 n. x# J' D9 i) V2 ^#define ASSERT_SYSTEM_( _op, ...)
" `+ M* q4 P% g# B namespace A{" ], v/ q3 m8 F" h# t3 Q
}
, U V: t4 G2 |#undef ASSERT_SYSTEM_
& `# a: c; {5 X) E. n4 @# m- E8 O#define ASSERT_SYSTEM_( _op, ...) if( !bool(_op)){ std::cout<<"Assertion_Failed(System):["<< #_op<< "], Hint:["<< ___SUPIMO::Debug_::__ToString_items( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< ")\n"; EXIT_;}$ E( r4 J: A4 r3 ?1 i, c4 y/ j5 u
1" ^! a) @6 L5 w3 A: ^ q& i
2# k8 v) b/ }; |( m6 [
3. r( G( f( T( O% l2 h* _
4
- g9 }/ Z7 N" w9 x5; Y; Z4 K" D. b3 w* d0 [6 o
6+ d# b k7 }4 N- F# l
. 也不可以不写#undef, 但他会有警告warning: 'ASSERT_SYSTEM_' macro redefined;5 \! N3 I$ a0 z) q) C1 n9 e7 \
& v( [3 ~ T: T/ P$ J
@DELI;" z d4 ` y7 j4 z: l# B
# j) F% H0 Q1 b- i' c1 m; `# L& \
ASSERT_CUSTOM_: 用戶自己的程序裏面 使用這個宏;: t7 s# v, {% G. }6 ]1 {6 [, a
ASSERT_SYSTEM_: 算法模板裏面的報警 都使用這個;
9 R6 g* _4 q/ c3 v; {4 Y, D/ S% E" S, s/ ?% X* Z1 o
宏9 [/ P5 \1 O2 Z1 V0 z
為什麼FOR_的宏定義是 (int)_r呢?
& W" S/ ?( M/ e4 s對於uint32 a = 0, (a-1)的值 是111...111, 於是for( int i=0; i < (uint32)-1; ++i) 這會死循環的;6 i4 n" R6 J6 @$ F5 ]! C
但是 把111....111 強轉為int, 她就是-1, 即int i = 0; i < (int)-1; ++i) 這是正確的;
/ y# f k' |! |6 g1 B) o; S" t6 g# b! b; j
@DELI;; I @- r( w6 p# y* `
$ |6 v) q7 E* Z/ Z( C這3個報警宏 都有2個模式:
: [ H" ?1 ?' ^! G8 y. M1(默認模式):[如代碼所示]; ? l% V1 n3 N) {/ T s
2(優化模式):[你自己把他注釋掉, 這主要是為了(提高程序效率/便於找到程序BUG)];" o1 z/ g% r( A# J* O. s3 G+ a, F
. 比如默認版本是#define A x, 那麼你就把他改成#define A (void)0 // x, (注意後面的注釋// x是不生效的 預編譯時會被清除掉 即到時候是(void)0; 而不是(void)0 // x;)
- ^! p) s. [! r6 n8 b M, [/ X: g) p C# K
ASSERT_MSG的優化版本 即static_assert(false), 此时在开发阶段就會報錯 也就是你會發現所有的調用ASSERT_MSG的位置, 就可以发现有可能存在的错误;
% d p* F0 R) J: o
p2 M9 T. o9 d8 `" i, H. i, p@DELI;
) l; b8 F" e, k2 b: w0 _$ `) z# U- ~3 D. e6 b2 t
#ASSERT_MSG_( _msg)#
: L. M4 @0 r5 A2 U9 l这是完全给用户提示的 程序无法测试其正確性 但你自己必须保证他是true; 比如取模除法 mod必须为质数, 就可以是ASSERT_MSG_( "mod必須是質數");, V" _) g5 T9 L$ U- m
, ~6 \& N" M# |. a5 g$ d@DELI;
: t, L* R. I7 P' q0 Z$ K( h
% ~9 ?# k: ~1 w8 X) |0 D#ASSERT_WEAK_(op) (void)0#
) p" {: R& Z- O# Y5 g2 y即使op为假 也不会报警, 但你自己要保证他一定是true 这是为了效率;
7 g |6 ~* \6 v' P5 l5 O: d# w4 b) W" O/ q
Modular
' d, z# m0 J6 M4 UModular的設計思想是這樣的, 她有2個模式: 對於using MOD = Modular< T, X>, T必須是有符號int/int64/128;0 U/ e. M$ Y; @. C- B; x
1: 你的Mod模數 是不變的const常量, 此時 這個X是常數, 即在編譯期 模數就固定了;3 L6 I v% s/ Q4 T" m$ u
2: 你的模數 是可以改變的, 此時這個X <= 0(你任意設置一個值即可), 此時到了運行期 你可以動態的通過MOD::Set_mod( m)去設置他的值 且這個m參數的值 即模數 她必須是在T的正數範圍;4 F/ M) Z. L# A1 A
不管哪個模式 假設你的T=int 你最終的模數 一定是在[0, 2147483647]的範圍內的 (而不是uint32的範圍), 而且你的值Value 一定是unsigned T類型, 為什麼要這樣設計? 因為 當你進行加法運算 此時 你不需要轉換為int64 她的加法結果 一定是在uint32範圍的;
1 A( G# x3 N' g* t+ P) J; X
6 \7 z# b$ f! M; j1 G# ~) f@DELI;; w) B9 _9 C' E
, L7 j' e% i* C2 c; c對於乘法操作, 如果是int32/int64 則直接轉換為int64/int128來進行乘法, 否則對於int128 則執行二進制乘法(她會調用取模加法 是不會溢出的 這就是為什麼你的模數 必須是有符號範圍);
5 \ f/ `! L/ S) H9 r: x$ r. j$ {1 D q7 G4 q: o5 l2 m2 n
@DELI;
7 b q$ J7 D0 f! U9 K3 R1 E7 M0 N' g
template<class _T> Modular( _T _v)這個構造函數裡 你不能對他進行is_integeral的判斷, 因為對於__int128 他不滿足條件(可能未來編譯器會支持 但現在他的返回值是false);
) M% K0 k) m0 X# M% Z, n! f, I3 z; Q
@DELI;5 G9 ^' @* a( K
, j$ ?) c {0 |) l+ Y3 ]基本使用, f1 G) _4 v n0 q6 w& U
7 T$ V6 n; g! Zusing M1 = Modular<int, (int)1e9 + 7>;3 u; b. g% Z% ]. u9 C
所有`M1`的對象 他的`Mod`都是*int常量*;, }9 k5 k+ ^6 H$ v9 h9 Z" d
- V* i, E. R* b1 Y7 Jusing M2 = Modular<long long, (long long)1e15 + 7>;
% j2 c6 L& |7 w" X所有`M2`的對象 他的`Mod`都是*long long常量*;2 j- H0 D3 `1 z" O1 j6 g! I
$ H" z% F% e, u7 o. q, b* x
using M3 = Modular<int, -1>;8 Q% k6 U0 g" W, Z4 B5 B
M3::Mod = ?; // 由用戶錄入 (這行代碼必須在*運行時* 即放到函數域裡); e7 K, C: I% d
所有`M3`的對象 他的`Mod`都是int類型 且等於`?`;
9 E1 Y. l1 q! J# C A; y, C. Y& f0 H' l- C% Z) W/ |0 Z
using M4 = Modular<long long, -2>;# ~/ ^. p: I0 q( B
M4::Mod = ?; // 由用戶錄入 (這行代碼必須在*運行時* 即放到函數域裡)
) H6 W8 Z6 m4 x所有`M4`的對象 他的`Mod`都是long long類型 且等於`?`;+ T" ~% l( G4 K" G, ]( E0 r$ |/ x3 ^* v
' m" \0 Z, Q+ ~6 w& P" W. d
using M5 = Modular<int, -2>; // 注意此時要和`M3的<int,-1>`區分開來 即不能寫成`-1`, 否則`M3,M5`就共用同一個`Mod`了;
% ^4 o) d4 g2 G2 c. V2 R& b
) e+ V7 y! a( l- b8 I2 R2 M
6 B8 Z0 a+ m/ c) |* r! Z! S@DELI;
{% S& M! g. V' V7 ]0 x6 \5 I4 t# Z, _
T_ Value; // 一定是[0, Mod)范围; 不要调用`obj.Value = xx`(他不是规格化的) 而是使用`obj = xx`;
! E Z( ?% B+ J Y, y19 h( @& N1 a+ X1 A
#除法#/ d6 k3 t9 J' u/ a
调用a / b的前提是: (1: Mod是质数), (2: b != 0);6 ^- R5 k! S; _% D, j
- a( D3 o8 }! O7 Q@DELI;! C+ ~) `- \ V" d" G5 c- E
. e$ \4 U, j2 `#BinaryMultiply#- @' b2 e1 s4 j$ z
使用a*b(重载乘法)的前提是: Mod * Mod <= INT64_MAX; 如果是Mod+Mod <= INT64_MAX 就不能使用重载乘法了 可以使用当前的二进制乘法;
! b# W" T+ R. l& q2 Y
) T6 m" N& A( i@DELI;* k8 O6 P4 I* x
$ `1 A4 e$ K' L) A# p
#__Cout#/ W$ {/ b( D5 ~" m- v
这个函数的目的是: 特判, 即对char/string/const char *的输出 重载, 之所以不是放到<<重载运算符函数里, 是因为 如果是<<重载 这些基本类型 就和系统cout的内置重载函数 冲突了;
& t+ S1 K+ `$ m( ?也就是, 比如对于vector的重载 是放到operator<<里的, 而对char的重载 是在__Cout里;% R8 g) V" X; m+ D( `
) A2 U8 `7 y ~
函數/ r1 r" \: M# k$ d
#IsInInterval_#
- F! d4 \: F& u( V9 ]. IsInInterval_(c,l,r, true): 判斷是否滿足`c>=l && c<=r`, 即在這個區間裡;+ }- z; f* `4 K9 |/ U% `
. IsInInterval_(c,l,r, false): 判斷是否不滿足`c>=l && c<=r`, 即在這個區間外;
+ ?7 G- A8 D* X$ H2 B7 L2 F1
y" u% l- h3 l- w" b9 M- G2
! q5 d0 M- q8 Y( s30 R1 d# g j- r7 i
Integer6 T; w1 H+ W+ r& v& W5 F: b8 N
GetPowerRoot( a, p), 比如令T = a^{1/p}, 则返回值为T的下取整;& X. o9 D& u* s( K
6 V1 a: w B+ |8 _1 Z2 Q
@DELI;
$ A9 @3 k9 Z7 W
! P% X& y2 e( ~. u5 OVectorToInteger和IntegerToVector是互逆的;
9 i& ?& r3 V0 t. m2 d3 X) K- w數字的高位 就對應 Vector的開頭; 這樣設計是因為: 對於一個整數321 我們通常是從高位開始閱讀 因此高位對應vector.front();
3 A5 N2 \9 m# N4 r9 F% ?4 x. 比如, 整數321 (3是高位 1是低位) 她對應的Vector是[3,2,1] (3是開頭元素);( y. v5 d/ ]* l* J; o2 ^) O" j: G
7 f' ?5 S& R+ ^( V@DELI;
9 P# m: J" i9 @: X
: z4 t0 N8 \! b5 i) B1 y! l! P5 V使用该模块里的任何函数 都是谨慎, 最好就是在调试期间调用, 你要充分考虑好他的实际效率问题;0 z0 |0 {& r4 t% K
比如VectorToInteger( {a,b,c}, 5)这个函数, 其实 你可以自己手动写成a*5*5 + b*5 + c, 没必要去调用这个函数, 因为此时你已经得到了{a,b,c} 他的长度是明确的 去调用这个函数 反而效率非常低;
* i& A# s; Z- U! R" u
- N! V* x6 E8 [; Z; F1 U@DELI;1 ?/ F0 J0 _- f3 z$ d& P+ C' j- ]
+ \+ x) f# a& I$ rvector<int> IntegerToVector( _T _a, int _len, const int _radix);
& L3 f& S3 S0 i比如a=10, radix=2, 他對應的2進制表示為1010, 那麼此時你必須保證len>=4 (否則會報警);
& b- M8 x8 N. d) E( h. @IF(len==-1):[答案為[1,0,1,0]], @ELSE(len!=-1):[答案為[0...0,1,0,1,0](即前面補充前導零 答案長度為len)];
" x) c$ ?! l% }1 I8 @
`5 F, t; ]. J9 u0 d7 g, {4 b@DELI;. }- o6 s; D2 M7 B6 N& F) X! t
9 i6 e7 Z' l) d. E) OSqrt( a, p)$ q( S9 x' \/ E8 s7 `: P( I* r
要確保a>=1, p>=2, 假設答案是浮點數b 且返回值是b的下取整;& A: N0 Z. _8 ^; Z: ^
這個函數的主要目的是 判斷a是否是p次冪 如果是則返回其p次根;
0 c ^$ q) e4 ]/ x. 由於b = pow( a*a*a, 1/3), 此時b可能是a-1/ a, 而答案是a, 所以要判斷 是否b+1 == a;! [2 |# _3 W8 B8 m
$ @/ L5 U" d4 i4 V/ A6 _7 j@TODO- i8 E- e/ z, U7 F
Modular里面, 我们用unsigned T来存储结果, 但实际上 你的取模值 一定是[0, T)范围的, 即只使用了一半, 这是因为 当涉及到+-时 此时不会溢出;$ U! w7 o7 J) |* f
. 但这有缺点, 当你Modular a = -2时, 此时构造函数是-2 % 5 他会变成int % uint -> uint%uint 即-2会变成uint 这就出错了!!! 因此要写成int%int;( e. I, b' W$ m
最好是, 你就用T来存储结果, 当相加时 他虽然会溢出 但其实他还是正确的! a += b; if(a<0){ a -= Modular;}就可以了;
* G, S6 u5 R3 y7 y2 [: ~: m: z x8 @1 V
错误
) Y8 v4 @ ?( ?) v( jis_floating_point_v< Double> 他是等于0的! 因为Double是我们自己的自定义类型;
" T6 }! Q. s9 U# [你可以写以下代码后, namespace std{ template<> struct __is_floating_point_helper<Double>:public true_type {};}, 此时 就可以了;( `! W* z( s; |. h/ g
/ _/ q8 e$ C F7 w& B/ X# E算法模板编写规范4 u9 V' t& Q( Q+ k
错误
# o! |6 ?, H, M! U) p模板类 不要写构造函数, 因为我们可能写到全局域里 ST s(而不是ST s(??) 此时不能有参数;9 A1 A6 a& Q; z$ f& N1 ~
! \, X* _4 |# Q7 E& |# T
@DELI;
8 @9 \: D8 {9 K1 P4 T% G C# I5 [. Q, h7 n( r' {+ H4 r k
不要写namespace ST{ using T = ?; vector<T> DP; void Work(){}}这种代码; 这样会导致ST是一次性的 即T是唯一的; 然而namespace不能加模板;
6 V5 A7 P! ?) c5 V( L4 K一种做法是: template<T> struct ST{ static vector<T> DP; static void Work(){} };, 但这样有2个缺点: (DP需要在类外定义 因为他是static), (由于ST是类 而实际上 他里面都是static的 不会用到他的对象 这就违背了类的初衷了);6 i- i H' E0 o& m! Y' M9 w2 p$ I! {
最优做法是: namespace ST{ template<T> vector<T> DP; template<T> void Work(){ 使用DP<T>;};
( q8 B4 _. m; L e; ^
8 V+ \) U6 [/ n/ T4 `9 \. B3 v' c性质
~; w. A+ e0 A3 n' p7 X5 ]模板类里放大数组constexpr int N = ?; int Arr[ N]; 等你用到时 再把?赋值, 这种方式 他确实是效率比vector<int> Arr要高, 但有个缺点是 你到时候的类对象 就不能放栈空间了 需要是static ST s 否则大数组就爆空间了;1 a8 z0 K& q/ o. i
: R* O4 l! k8 C, ^- k. ^2 A@DELI;
2 z7 u; C& p7 N) u: Q& ?8 |
( O( B' ]* Y/ |5 r! E& I不需要寫一個TODO_STATIC_的宏, 對於靜態的@TODO, 你直接寫成注釋即可: @TODO: xxx, 然後實際使用時 再把他給注釋掉即可;+ c" G$ u# f2 Q; ?. Z0 W
; x& b+ p- ^2 c% B2 |& c
@DELI;
2 e8 @+ P0 J- V5 I5 v. z- v, m" \* `6 {
#讓某個函數 必須在程序開始後執行一次 且只能執行一次#8 K4 R, J$ @ @
8 T, J* T7 O/ L
void Init(){
+ V1 v y' i' n8 H, [4 \. X$ p( N EXIT_COUNTER_(2);
; u: A% Y0 }# ^}
! v5 r6 n; f$ K$ f8 P |% k@TODO: Init();+ o1 `7 s9 C1 D
1
% W+ I8 N7 K0 R; j3 @' P" p2
* M: [ E1 U2 P8 G3
0 ~. j0 V5 J& E* ]$ y3 v" X9 e @3 F46 d* ]" O8 \1 d, m
這類函數 通常是不可以有函數參數的 (比如篩質數函數), 也就是 她的參數 是根據題目的最大數據範圍 而不是錄入的值;! ~" c) a7 j7 ^! b; D! u! h
8 J: u0 G9 V/ G5 `2 R- p7 x
不要用__attribute__((constructor)), 她是報錯的, 因為他不是在運行時執行的, 而我們的需求是在運行時執行;
( \1 u6 j8 V* B" w0 q
- A' {$ S( a9 @* y@DELI;; \+ [3 L2 X+ y! o
% T( P6 Q7 x7 P
#類/命名空間的Debug調試#
7 {$ O3 j0 J3 @- E* @5 N0 K: l) w' w8 X3 }
class ___X{) X6 l# l s7 ?+ o) W; s
friend ostream& operator<<( ostream & _cout, const ___X & _a){* X* M" z. e; q" I$ l0 v! g
_cout<<"\n"; 6 }8 y! ~+ e/ W; S, N
DE_( "___X-Debug-Begin");% i% q) \' t# h6 s. Y& R) `. f
1 f: X& W: U+ _% K( {+ d% @0 V cout<< ?; // 此時不可以使用`DE_(?) 或 `Debug::__CoutItems(?)`, 必須使用原生的`cout`;8 d+ J; o# x8 |
# c( K* |' R3 z% i/ P6 ^
DE_( "___X-Debug-End");
9 F) @$ j+ y8 x: S- \ }
% J$ r9 J# S+ Q" u4 f3 X}* }* U' V0 F- B9 o
5 t0 A( q% M! f; ]
namespace ___X{
, A4 E9 w% ]( B0 u, W3 p void Debug(){* m& X* ~1 C& q- Q
DE_( "___X-Debug-Begin");
) V1 `5 i- R: v. e" @$ c) M4 o3 X* s
' S# P8 Q, @# b( N cout<< ?; // 此時不可以使用`DE_(?) 或 `Debug::__CoutItems(?)`, 必須使用原生的`cout`;
' N3 u* R9 I# F; @3 G: t
, R ~- V) {: t& R' q DE_( "___X-Debug-End");% z. A. X# S' l% D
}
. T) S, y: @5 o9 Q}
$ l8 W k& w9 o. I6 |$ Y% o) n8 H" C
@DELI;
: h& n% ?& e% b
$ e2 ?. P& e* m8 a) e6 _6 }# |$ B/ C#嵌入模板的全局变量#
# r- u% H" Q9 ?% ?1 |- \# Z* h! B V) d" a
{ // ___XX/ u! U2 U$ U) E4 \6 M: y
const int ___Number = ?; // 这里就叫做全局变量; 要以三个`___`开头
. ]" F' t4 [" [+ S7 g int ___N = ?;) j; J; v: F' ?% a$ ~1 A
for( int i = 1; i <= 5; ++i){
4 ^4 q# J e- x: z int a = ?; // 像`i,a`这种*临时变量* 可以不用写`___`开头;$ A& P- V! b7 l$ k# n$ c. f4 \
}
4 e& {. F( y$ f) ~4 l
( d/ R& @3 ~6 s3 ^8 G# c9 I C} // ___XX
! t# B0 C! N1 v" I3 Q( _# M+ r$ d7 Y7 k/ G
@DELI;. k7 W3 D2 G5 P' H' P
; B6 u; }$ ^' c+ t* C1 l
#Initialize函数, 强制的放到构造函数里#7 ^# U3 q' a( D* ]5 r' }& m5 d
最经典的例子是(建图)) D2 h8 p, |, I3 P. s
/ y) q' Z1 O2 B) \1 Z, `8 vGraph( int _points_count_maximum, int _edges_count_maximum){}
" Z- H2 g: u" U) `7 Mvoid Initialize( int _points_count){}- A; D* k& p" x8 t7 {
1
: z! k7 ]/ q. z! b+ Y4 o# B& K2
! B# k# M, A& J2 a$ S% T6 I. ~. w这样分来 会导致, 每次使用时 必须是: Graph G( 100005, 200005); G.Initialize( n), 也就是两个代码行 (两个操作, 两个步骤)+ K8 \! H g9 E3 W, e
一旦忘记手动的调用Initialize函数, 虽然会报警, 那你还需要再去写代码 补上调用这个函数;9 Y: d. ^" K! Y" [4 w; u }
% R" u- m6 V. Q当我们将Initialize函数, 嵌入到 构造函数 里
% q3 H# X1 t- T6 m
2 u9 Y, E- A, X' T+ xGraph( int _points_count_maximum, int _edges_count_maximum, int _points_count){
1 ]8 A. @4 c. |! d ...
! ]0 O# f& m: w$ d: S //--! U& |4 n8 ^$ k1 S9 j) d
Initialize( _points_count);' ` ?3 Z6 v" G# G# [3 b
}1 q* r/ g, t) \9 V: }* G w5 Z# N
void Initialize( int _points_count){}2 } g, i C u
* I0 Q9 e) L, g9 N0 ~1 `注意, Initialize函数和原来是一样的, 只是做了两个事情:
5 L1 L; j# _1 @ q: | l2 ~8 K& P1 将Initialize函数的参数 接到构造函数参数的后面 (比如, 原来构造函数参数是a,b,c, Initialize函数参数是x,y,z, 那么现在变成构造函数参数变成了a,b,c, x,y,z)# V7 y. p$ m) C5 V$ \7 y ]$ J6 ^
2 在构造函数的最最结尾, 调用Initialize( x, y, z)函数;
7 f8 a, H6 ^! h( Z6 O4 w
0 G1 R0 {0 N6 ?7 ]@DELI;3 U2 X' ]: Z& Y% Y! O; K( m G
; |9 R! l: p9 x+ C. v#数组长度用函数传参来指定#
1 E: p _. S7 y5 A; a. v, q, I+ O
template< int _Maximum>
8 {* | s7 Z& h0 K6 `0 Cclass ST{. [4 |8 C" T, [; g) X# _
ST(){$ A/ F G' v! n# a/ w
array = new int[ _Maximum];
% @8 z. W6 s. }$ r }
% [% z4 [1 }9 c- d8 y1 rprivate:2 s& e* ~) y! @" n; G
int * array;
3 j5 O/ o- b1 e2 [" @};8 @5 _ H4 S0 @( [# V" b. h
5 c% h+ f9 i. M: p8 oThe above code should be replaced to:3 I$ E- R4 O4 o0 s- q
+ R9 i7 H/ {6 y
class ST{ g6 I, w0 R( A* n+ G) [
ST( int _maximum) S" O. J6 \2 x( C% d$ ]
:
8 Y' ?* s3 Q* D& |, O maximum( _maximum){. E, x# r9 N- X( [( d3 }1 b
array = new int[ maximum];
) e) x$ v& |0 h( ~; e/ j7 N }7 l! k. E- w5 d9 t$ U
private:* P3 y# R3 l: f& s1 a
int * array;' v S- }. x" W2 I( k
const int maximum;, e" ~3 T# C' l- G9 V+ V
};- |; o: `- k G% H8 h" k
1 e* B% o) H Z7 c6 F# w@DELI;
6 O# @; C1 u) {7 h* @. {笔记
2 o! f8 r. U# I; |有向无环图DAG# d" d0 t9 G) l% W
最小路径点覆盖4 U/ z8 H: U( J0 \
//{ @Snippet, `ZuiXiao LuJing DianFuGai (最小路径点覆盖)`" ?& z5 [' h# K1 I* n' @1 J& _
{
. s: J8 Y8 K5 O( P( P7 H9 g: X. N int n = `the points-range in the DAG`;
% K& I5 }0 _5 v //--
1 s1 i! M: k& w$ F" m, q. ` BipartiteGraph B( n * 2, `the edges-count in the DAG`);* j' b) Q1 w( K: e; u
B.Initialize( n * 2);3 [/ A- f* ]5 @: G1 s# O4 X3 F( u
for( int i = 0; i < n * 2; ++i){
* q. ^3 D1 e- g4 s! C if( i < n) B.Set_pointBelongingness( i, true);7 u% q9 W7 o1 {3 v4 Q$ o' N
else B.Set_pointBelongingness( i, false);
: L9 P8 J( _9 P2 y }
& S3 R# L! K* i( u4 l& O for( `s -> t` : all edges in the `DAG`){+ a% e6 X9 `( d& u/ r6 w
B.Add_edge( s, t, 0);
: n: @3 ~0 D" l' ]1 V# f* ^, ~/ [ }9 q# r9 M3 m# t8 B. z5 I1 Q
//--
7 S, D9 K. r5 E, q5 T& i( V; A& X; l Bipartite_MaximalMatch M( &B);6 T4 j, u4 N. a; R1 @
M.Initialize();( e1 Y' T# _, K& e7 n4 G2 t4 i+ k, |
$(n - M.Get_maxMatch()) is the answer;3 N, l( f4 S+ ^: G$ K# _5 x& Z
}0 ^. r* O* q/ ?& e
//} @Snippet, `ZuiXiao LuJing DianFuGai (最小路径点覆盖)`
: W3 [ v5 d$ d" W- J2 e1 y- F* V1 o* n8 q7 e
最小路径重复点覆盖, 最大路径独立集
. P( q) m: k) G, i; b# Z//{ @Snippet, `ZuiXiao LuJing ChongFu DianFuGai (最小路径重复点覆盖)` `ZuiDa LuJing DuLiJi (最大路径独立集)`
+ ~/ J" ~/ [2 p( o{
# U8 V p6 ^; {7 M1 o0 L+ z int n = `the points-range in the DAG`;
; q" R) g- j5 o; u; u bool * edges[ @PlaceHolder] = $(edges[a][b] means a edge `a->b` in the DAG`;
' F7 }$ N3 _6 u" x9 H4 ] //--8 \9 _, b% z# w/ R' F9 _
$(perform the `Floyd-Boolean` on @Var(edges));/ C$ s `$ R. W2 K1 C8 c
//--% r7 D/ I6 x1 J/ B
BipartiteGraph B( n * 2, n * n);" y: z, v5 m+ f: S' s% l2 x
B.Initialize( n * 2);8 m: T6 \4 E' R8 q8 X( A
for( int i = 0; i < n * 2; ++i){! }( y3 N7 ?6 q" [$ a( ~( [/ W
if( i < n) B.Set_pointBelongingness( i, true);
; {6 n/ i2 { \# Q6 X" l else B.Set_pointBelongingness( i, false);
^* B B1 r4 m# I- [3 z }6 B) J( H I& ^" c1 C0 x
for( int a = 0; a < n; ++a){) H3 _7 r! k; b! R! v
for( int b = 0; b < n; ++b){+ ^+ l! G# ~) X
if( false == edges[ a][ b]){ continue;}
: {: y3 t, e+ C; c B.Add_edge( a, b + n);
2 ]; _4 t8 K5 j: C! N }0 v2 n* w* q, k# [
}/ e0 I2 h0 ]1 S8 X2 U' ^, {7 m
//--
6 n% I0 G$ @- M Bipartite_MaximalMatch M( &B);3 n y r9 H/ ^5 D
M.Initialize();1 E+ t6 o) o9 a. v
$(n - M.Get_maxMatch()) is the answer;
4 g4 Q7 W- e' [( Q1 S/ P9 p6 N& W}; \2 J Q; h, p0 T
//} @Snippet, `ZuiXiao LuJing ChongFu DianFuGai (最小路径重复点覆盖)` `ZuiDa LuJing DuLiJi (最大路径独立集)`* H; L9 {7 p; U3 a
+ e+ @) j8 R4 d: l. ^) P7 u
DAG的终点
) b( E. ~% o0 l; R5 }//{ @Snippet, `EndPoints of a DAG`
( D+ p7 I) U* l0 z{
/ g2 z# K$ e9 r4 E0 t% ?3 d9 a int n = `the points-range of the DAG`;
3 @ |8 {) M& p0 w% ~ int * departure = `int ?[ >= n]`; //< the departure-degree of a point;
$ u* Q. X1 S! Q1 i" U; @2 s& ` memset( departure, 0, sizeof( int) * n);4 N6 j9 O9 [ D+ |. I5 {& r
for( `a -> b` : $(all edges in the DAG)){
- _2 E# w7 ~/ N3 Q. p5 | ++ departure[ a];
1 V; T; g# P: j! z' {1 k }
8 M- S# Z' g8 R: q6 G for( int i = 0; i < n; ++i){
, o5 Z2 d( g6 \, ]( g if( departure[ i] == 0){
+ B- ?3 j( g7 g ?//< `i` is a End-Point in DAG2 h6 ?6 G9 q1 T% ^
}
: g9 X. O- u: ~ }4 C" a+ Q+ I; x" W
}
$ _$ U0 L# _0 v9 }8 a//} @Snippet, `EndPoints of a DAG`1 ^) r( n, g7 ^# r' T
) @7 M) }* b- @% ?% |/ ]DAG的起点
, K4 l7 Y3 n3 W7 j g4 z% o+ e//{ @Snippet, `StartPoints of a DAG`. a, V4 i1 c' `" d$ N$ @
{
/ L# u% L, ^& n) H* \: G5 M int n = `the points-range of the DAG`;/ y: ~! p0 j0 k$ D; V
int * incidence = `int ?[ >= n]`; //< the incidence-degree of a point;5 e5 r! \1 w, U) U2 I8 Z9 p
memset( incidence, 0, sizeof( int) * n);
) b. C+ |- @5 U7 b+ [- u for( `a -> b` : $(all edges in the DAG)){
6 G& b6 q" |: M: C2 p7 x3 i/ o ++ incidence[ b];9 e7 M, ~1 y" C2 `6 }& c8 V
}
8 \5 K8 i; N7 z/ y8 Y for( int i = 0; i < n; ++i){& N/ N: }9 L B% O( m! E
if( incidence[ i] == 0){
% c6 C% q$ u7 t$ e. G, O+ {8 D. r ] //< `i` is a Start-Point in DAG
/ w$ U7 Q5 D" H6 x/ V- y }' w* M; z) e2 U; @* v& p
}
7 h! V# C) t n0 y7 q0 M+ r, K}. w! O2 L: Q% U( B
//} @Snippet, `StartPoints of a DAG`
7 X" P- N0 t4 n# W2 i2 s; v
# e' a- f# m7 U- m6 R- w判断一个图是否为DAG, 求拓扑序( }% Y9 r1 c4 K
bool Work(){+ ~5 f% t, s g* P$ }/ B
//< `1` Check whether a Graph is a DAG; `2` Get TopologySequence;: B- Y$ n7 c' Z1 E
int points_range = @Unfinished;
, I% b4 i; m% i; n4 x) a int * topological_sequence = @Unfinished(an outside array whose length must `>=` @Var(points_range));
$ c% J/ e) x7 s, T int * incidence = @Unfinished(an outside array whose length must `>=` @Var(points_range));
+ Z% y) X( ^' o memset( incidence, 0, sizeof( int) * points_range);# r. H _) u/ T$ z6 V, \, Z
for( `a -> b` : $(all edges in the DAG){
' o9 n$ d7 B$ z6 k1 d ++ incidence[ b];
- O, T0 m1 D# x. o3 j! q8 F2 S; g }
6 { T/ B. x) H! I# N) q; s& d int size = 0;
/ {- y* r: R7 t/ E; V3 j3 Q. N) M4 h for( int s = 0; s < points_range; ++s){
0 g9 S' X K0 K! B; l [, C if( incidence[ s] == 0){
/ C/ {& ?, L, I7 H0 F: Z# h$ c topological_sequence[ size] = s;
3 J& P1 w. E( J: b ++ size;% ^1 ]0 F4 M# v+ `
}1 {! p6 ~. E/ c( y6 L
}; P0 E, a4 ^* U1 `
int head = 0;
4 i. ~' I9 t) C/ C5 V while( head < size){
" j2 ?% c+ x! M; F3 y/ c3 t" z& I int cur = topological_sequence[ head];
% J" q: z. I7 H3 s$ |4 q ++ head;, _& `3 Z r: T4 @8 ~* C
for( `a` : $(all adjacent-points of `cur`){
+ M( H! A/ `$ i' h -- incidence[ a];
4 {3 G# \8 d5 i if( incidence[ a] == 0){
& k" [/ r2 a% u, U topological_sequence[ size ++] = a;: ~. v( e% E7 U+ U5 O! g' d
}
( |0 \% \7 m0 a( }- u; |$ u }7 @, H; C( k0 g7 s1 ~; O, O
}
- J3 z8 Q+ a" d! V' o1 K if( size != points_range){
$ w- m4 ?% r$ j$ ~2 i* L, D return false;
, P( L3 o' { i( R5 [ }9 H4 b J5 H3 C* }* Z
//>< The answer Topological-Sequence has been stored in @Var(topological_sequence)" K& n& o0 W6 d2 g) M6 f+ Y) C
return true;
0 b( N, d' {0 m5 t}
7 _1 e8 ~& A X! }1 t% H7 S" S9 w* @
. ^# s) T; a- |$ D* G4 }图论
* b& y" q3 f- C最短路0 k' L7 ~3 j0 q, @* ]
TARJAN
s2 C) I, y6 c$ _$ i9 @. T2 s( c9 t无向图-PBCC点双连通分量
7 ]) V! U/ T% b3 A* T, r+ 割点/ I T, a7 e- t) f) E
" o. S0 x' Z- ]' D1 n! d//{ Tarjan_PBCC-Declaration: B6 S9 _; x3 I# \0 G2 Q3 I& R
template< class _Edge_Type>% g2 ?7 L! R& {! g# p2 g5 I/ m
class Tarjan_PBCC{4 q% B/ D9 {* c. g( r' S
public:
, j5 r) Q$ r n# G. d! V( i const vector< int> * Pbcc;9 {* M9 U0 G- a' B8 Q- p! ]/ l6 e# b
const bool * Is_cutPoint;+ G# j! N: z+ T
//-- variable ends4 O( ~* L" a$ R# {" L- ~# \. n. {$ U
Tarjan_PBCC( const Graph< _Edge_Type> *);; g* C" t# i7 B; @7 n2 O0 |
void Initialize();; m: d9 f" _" _0 F( ?% e" H
int Get_pbcc_count() const;
' E( A/ U1 N) m2 B1 Nprivate:! ^- }) l4 n$ a% W3 C
const Graph< _Edge_Type> * graph;
: M- W) E2 c$ D( o3 o int * stack_;& ?$ \0 }9 c. n# }% j b9 F# F
int stack_top;; o- ?; y# x6 [
int * dfs_id;9 p% |; ~ G2 W$ h
int dfs_idCounter;1 I5 u: U$ R+ C w. X( _7 _. s5 `
int * low_id;, D& }6 |. a: v* b6 Y& z' W. I& O
vector< int> * pbcc;% x/ w* N4 H6 j' W+ j
int pbcc_count;/ t! t% P! Z% W+ {6 p, A
int dfs_startPoint;
. M$ G; Z! L0 W a Q6 E; h1 i bool * is_cutPoint;5 B/ p: Y. l0 g5 I6 i8 J: g
int cutPoint_count;
! o. `- }1 [$ U4 t, k8 { //-- variable ends- E z n: [, X3 i( b
void dfs( int);
/ e+ @9 E! h. y1 H; s};( y I2 k( t/ |6 F! B
//} Tarjan_PBCC-Declaration
. T3 K/ {* P" Q( g& ^
7 W8 N) E, T% N( l//{ Tarjan_PBCC-Implementation
8 M% I* i; O( z7 j( D* ` //{ Variable-Annotation
& `9 L# K# q; s l //{ @Var(pbcc)
/ ^" O. f* _0 P' d- ~2 Y1 B/ A // + `pbcc[i]={a1,a2,...}` means that the PBCC with id `i` consists of these points {a1,a2,...}+ A; q5 |: y6 P% t0 l' Q5 @
//} @Var(pbcc)
8 A# c [) }1 P- L //{ @Var(graph)
5 n! s; P2 U) k! w u // + must be a undirected-graph, i.e., Edge[i] = Edge[i^1]
$ [8 J" o' i) K7 Z1 } //} @Var(graph)
+ s+ P) M# ~$ z& o6 R //} Variable-Annotation# }* t: T$ M! n. W, N& |& S' T
template< class _Edge_Type> int Tarjan_PBCC< _Edge_Type>::Get_cutPoint_count() const{ return cutPoint_count;}* h8 Z4 Q# g+ L. Q* l' b7 r" i" p
template< class _Edge_Type> int Tarjan_PBCC< _Edge_Type>::Get_pbcc_count() const{ return pbcc_count;}4 d& R, P# g- V% _
template< class _Edge_Type> Tarjan_PBCC< _Edge_Type>::Tarjan_PBCC( const Graph< _Edge_Type> * _graph)/ P1 m. e9 S0 C, @$ Y2 X
:9 v% ]3 W: x( w
graph( _graph){% g: |! { k# p8 f: E: I* s: M) _3 k
stack_ = new int[ graph->Get_pointsCountMaximum()];
# R! [7 X) J% m+ @( u. C" ^ dfs_id = new int[ graph->Get_pointsCountMaximum()];/ R9 R1 [: X) s' M: N/ Y$ D
low_id = new int[ graph->Get_pointsCountMaximum()];
7 j" @7 P% r& H" }; n; }: i" i pbcc = new vector< int>[ graph->Get_pointsCountMaximum()];1 ^& }2 Z7 Y0 ]; {: I4 z `
is_cutPoint = new bool[ graph->Get_pointsCountMaximum()];4 j5 F- g9 ^& _
//--
) _/ k! g! b" L7 m Pbcc = pbcc;
) g, x$ K2 x& W/ v Is_cutPoint = is_cutPoint;
2 g" R3 \6 L% S- Q}/ Q' H) [! [% E7 i. a* `; f( P$ K
template< class _Edge_Type> void Tarjan_PBCC< _Edge_Type>::Initialize(){
$ H4 L. B+ d' ~; i stack_top = 0;8 E( f$ V! u" X) k4 X" X$ D
dfs_idCounter = 0;
) ?' g8 K( p& Q0 x! w/ U- _3 p pbcc_count = 0;4 X, m) A0 ^! Q# d% I8 D" t; e$ g
cutPoint_count = 0;
0 R& K9 o' ?( u6 {( V for( int i = 0; i < graph->Get_pointsCount(); ++i){ pbcc[ i].clear();}
; Q1 ]/ @2 b8 v3 Q memset( is_cutPoint, false, sizeof( bool) * graph->Get_pointsCount());
. r- W* e# b* Y- v! u memset( dfs_id, -1, sizeof( int) * graph->Get_pointsCount());/ V0 U1 s6 E9 i8 N; J
for( int i = 0; i < graph->Get_pointsCount(); ++i){
# H# c9 S% h5 P4 y* Q& D( f% Y- {9 h if( -1 == dfs_id[ i]){
5 I8 W5 s( h) L2 [5 n7 E$ s dfs_startPoint = i;$ z4 `" q, w' @6 v' x6 f, @
dfs( i);% d& T. n4 Z1 \, s1 `
}; a3 x$ w, w4 r& ^% o5 `
}/ x3 [3 t2 ~: w) Y+ l
} m" W& x8 D& ^- _; l
template< class _Edge_Type> void Tarjan_PBCC< _Edge_Type>::dfs( int _cur){
) H7 Q& j; M: q" W5 X stack_[ stack_top ++] = _cur;& z# j. A# {: `2 x9 V) f
low_id[ _cur] = dfs_id[ _cur] = dfs_idCounter ++;
% o4 D$ Q7 d8 G- A //--
7 ?5 I5 f% c+ b1 Q' C int cc_count = 0;8 q& N: i* w+ L) _- F. ~1 h
if( _cur != dfs_startPoint){ ++ cc_count;}
4 C2 ^: g' W" U) o, O8 ^5 O" v for( int nex, edge = graph->Head[ _cur]; ~edge; edge = graph->Next[ edge]){# @# Z6 B/ r0 Y) y4 J1 n
nex = graph->Vertex[ edge];% O# p' m5 h9 W8 [) J6 E" s) A- K
if( -1 == dfs_id[ nex]){
, T2 {1 s% e- H6 R/ a dfs( nex);& X5 K) p$ `* Y+ i9 ]+ I
//>< `low_id[nex]` always `<= dfs_id[_cur]`6 i% d V6 \+ R, C* @, \- Y. f
if( low_id[ nex] == dfs_id[ _cur]){; v: a& _8 r# G+ }0 s: x5 Q+ z
++ cc_count;* l# k1 Y2 t% H9 S; V: P" F
if( cc_count >= 2){
# e; E: e' x/ {2 I3 A is_cutPoint[ _cur] = true;! D w; v) A% D% T* C( J! q
++ cutPoint_count;
% J) Y& v( s% Q# C8 Z5 E! I+ m5 L k, Q while( true){. z8 x- a0 k& G2 m8 ^
int c = stack_[ stack_top - 1];
) O# U: [# n# R! @& e -- stack_top;
3 I, b; K- \" |: D" P8 I1 _ j pbcc[ pbcc_count].push_back( c); //< the pbcc_id of `_cur` is not only `pbcc_count` if `_cur` is Cut-Point; i.e., any Non-Cut-Point must belongs to a unique Pbcc, while a point must belongs to `>=2` Pbcc when it is Cut-Point.
$ ]9 b+ g$ l% [6 Z" q8 T% ~% v3 I if( c == nex){ break;}" N; A8 @) U$ C) @4 I
}% w7 m. D1 ^6 X
pbcc[ pbcc_count].push_back( _cur);7 P" w1 x! Y) f
//>< `pbcc[ pbcc_count].size()` >= 22 E7 M" Z2 p) W
++ pbcc_count;" t/ M; N6 x' ^* ^: F
}" u4 m- T$ Z$ @
}8 U0 }$ s$ g" i; [8 `8 P
low_id[ _cur] = min( low_id[ nex], low_id[ _cur]);9 [$ I) X/ M8 j$ g! E* l8 a
}
N, Z& _/ v6 `5 u else{ //< `nex` must on the `stack` due to the graph is Undirected
: x* l! @- K5 l Z. m8 Q2 r low_id[ _cur] = min( dfs_id[ nex], low_id[ _cur]);% Y; J9 ?% ~- [# c& a4 `
}
8 S% k, P) @7 p% R: F$ L; J7 b }
4 ~( E' m4 i1 j0 \ //--
. }, o* b- h4 T1 y$ `6 z9 m& E if( _cur == dfs_startPoint){
$ L5 }1 N5 j4 {# e5 t/ B& d while( true){
0 t8 C2 w+ |* l int c = stack_[ stack_top - 1];
( j* ?" f. x* D' l+ o -- stack_top;
& y6 l. | t6 F pbcc[ pbcc_count].push_back( c);0 o0 N& V7 z @9 S) ~! W
if( c == _cur){ break;}
, k1 r# o$ X' k }
$ ^( D" ?0 U! e8 T3 D ++ pbcc_count;
& U1 {, g0 s9 t& u( R9 n }& _/ p, e9 D7 C/ H
//>< `cc_count` means the number of Connected-Component when `_cur` was removed from the current Connected-Component (whatever `cur` is Cut-Point or not);
, s" r3 }& I# B1 _$ Z}
3 W; c. Q+ k0 p% B2 U/ S$ H//} Tarjan_PBCC-Implementation, W8 L9 Q% j; E- w) \% S" m
- g+ R) s: N) m8 z4 x$ R
无向图-EBCC边双连通分量% e- w+ Z6 K' Y. `
+ 桥
; _* r! {2 ?# D N5 Q' s' a* |2 f# l& a6 T
//{ Tarjan_EBCC-Declaration$ O* f) \- ~- ~& J* D p
template< class _Edge_Type>0 }0 k1 |1 ?8 w% M7 s/ X9 f' ]6 e
class Tarjan_EBCC{ d- s2 l* R7 ~4 n8 g+ _, f
public:
7 o5 Z, D* C1 }0 }% q F# f5 X const int * Ebcc_id;) V2 ~1 o3 F+ i1 ? F5 H$ n
const int * Ebcc_size;: x- Y2 C8 C: d2 D, W6 W9 _" _
//-- variable ends1 `7 _ ]1 p6 j7 W J
Tarjan_EBCC( const Graph< _Edge_Type> *);/ q9 h" B: ]0 y0 m
void Initialize();
8 y) c1 r3 H' v, h4 Y" M! d int Get_ebcc_count() const;4 c6 \1 f# C% X/ K; j) f
const Graph< _Edge_Type> * Build_tree() const;
6 N* Y* I& D- [1 h* M6 V, {private:& e7 S. I$ B+ n; D
const Graph< _Edge_Type> * graph;8 w; G& d! @1 t& G% n4 Q
int * stack_;
( s% Z. w3 l3 q& [2 s! T int stack_top;
% G5 A Q' K) x+ }# l' P int * dfs_id;! b. H& C# z, r' m
int * low_id;+ C; y+ F9 }5 @% w# H
int dfs_idCounter;
0 x; \! m, d" Z- A4 C; P/ s. m int * ebcc_id;
8 U1 G0 ^9 n. @* c4 j6 P- P9 @ int * ebcc_size;
1 @# [* N1 c' s( C/ S3 N! V/ ^ int ebcc_count;( a! Q+ k" p, V4 b* Z* B" A
//-- variable ends
0 Y1 s0 S" S& @+ C, [ void dfs( int, int);
. x% `9 j7 W" m3 }};
/ j5 y4 n8 u/ h//} Tarjan_EBCC-Declaration" W+ K& j6 F7 V M9 o9 ~
) O3 u' D$ l2 E//{ Tarjan_EBCC-Implementation) c, p' Y6 y% A/ N2 o4 ^. L
//{ Variable-Annotation' b; j) A" R/ K* {) z9 C
//{ @Var(graph)% i0 g' x+ n E6 X( `2 i
// + must be a undirected-graph, i.e., Edge[i] = Edge[i^1]' \0 Z/ ~3 ^. T$ f
//} @Var(graph); r, e% i2 B, {. M
//{ @Var(Ebcc_id)
/ _- w% g7 e7 q* `% L: F' E // + `y=Ebcc_id[x]` where `x` is a point of @Var(ptrRef_graph) and `y` belongs to `[0, @Func(Get_ebcc_count)-1]`+ O' Q% `6 u3 ?
//} @Var(Ebcc_id)
; @% |5 f1 S! f$ C6 v9 f //{ @Var(Ebcc_size): R) P- r/ S. J- I# R
// + `y=Ebcc_size[x]` where `x` belongs to `[0, @Func(Get_ebcc_count)-1]`, the sum of `Ebcc_size[0,1,...]` equals the points-count of @Var(ptrRef_graph): G8 ]6 ?. f+ c6 J
//} @Var(Ebcc_size)1 z) d: { d* N
//} Variable-Annotation
; L' g. X" K( ?3 S2 |template< class _Edge_Type> Tarjan_EBCC< _Edge_Type>::Tarjan_EBCC( const Graph< _Edge_Type> * _graph)
u7 s& F& r: A7 i/ v( j :' m# t* `2 E: ^3 K p0 u
graph( _graph){
* g: l/ F5 s* s/ ~, x stack_ = new int[ graph->Get_pointsCountMaximum()];3 T4 O2 e# j7 I- |+ s8 A) ^
ebcc_id = new int[ graph->Get_pointsCountMaximum()];$ Z5 j& M, B. z
ebcc_size = new int[ graph->Get_pointsCountMaximum()];
8 y( x6 ~3 d+ R& p$ j8 y dfs_id = new int[ graph->Get_pointsCountMaximum()];
+ ~- A$ u9 G: V% M+ C+ _. y low_id = new int[ graph->Get_pointsCountMaximum()];
$ B8 U, O: ^& V/ X //--) ]4 C9 S D9 Q3 x% I0 V, ~
Ebcc_id = ebcc_id;2 o0 v! w5 n* |, E+ |" U
Ebcc_size = ebcc_size;
+ |3 w& e. \0 u0 [ x3 r} ]/ Q0 g+ m" s# a' x, a) O2 O
template< class _Edge_Type> void Tarjan_EBCC< _Edge_Type>::Initialize(){4 E7 h+ K, a9 S( k5 _1 q& N" T
stack_top = 0;& T* m; }9 C2 A- G
dfs_idCounter= 0;
1 M3 M6 Z+ `, v$ K# b ebcc_count = 0;, Z; D! D- t- u! \
memset( dfs_id, -1, sizeof( int) * graph->Get_pointsCount());
$ n5 A) m0 A: b4 h for( int i = 0; i < graph->Get_pointsCount(); ++i){# ?6 [2 }2 g$ Q, U# l
if( -1 == dfs_id[ i]){' h. [4 u' H; R A
dfs( i, -1);$ M# v; X5 C% T% H) Y, ? ^
}
. X+ r% s- U: s }
y j3 e" u5 s) _: ~, ?( f. l6 T+ `}
* G3 G: @6 }$ R8 @3 ?5 |template< class _Edge_Type> const Graph< _Edge_Type> * Tarjan_EBCC< _Edge_Type>::Build_tree() const{
0 w& U% b4 Z0 l4 G4 o//< + Make sure @Func(Initialize) has been called
O, P/ W$ F8 b' j. r. }//< + There is at most one undirected-edge between any two points in the Tree (i.e., @Ret)
' |% m) p+ J% I: N Graph< _Edge_Type> * Tree = new Graph< _Edge_Type>( ebcc_count, graph->Get_edgesCountMaximum());
' S9 w9 B* Y+ @+ E0 p Tree->Initialize( ebcc_count);# q2 L1 j! D2 M. ?# w
for( int a, b, i = 0; i < graph->Get_pointsCount(); ++i){
; ~* D7 I+ ?8 s$ }8 X+ C for( int j, z = graph->Head[ i]; ~z; z = graph->Next[ z]){
: Z8 I$ M5 r4 h2 `' H1 v- ` j = graph->Vertex[ z];% A( E% [ f& {0 [: \2 b& H! }
a = ebcc_id[ i];5 ^& I: K! \5 B+ A$ Z9 N& S
b = ebcc_id[ j];6 g, J) Z+ s$ t5 J) C8 @
if( a != b){7 R! P# L4 q: X/ D$ `8 C
// Now, there must has no edges between `ebcc_id[ i]` and `ebcc_id[ j]`% _- ^; W/ c( k3 U
Tree->Add_edge( ebcc_id[ i], ebcc_id[ j], graph->Weight[ z]);2 j. E. q9 s& w$ v* K# B
}
& g. I. ?4 a5 L }
# S. R1 U; c; W* d7 ^( C }0 a$ F- p, h6 F. A3 S% I
return Tree;
. R5 c2 O) y' R! V6 D* T}- d# W! ~2 K$ ?0 `) q
template< class _Edge_Type> void Tarjan_EBCC< _Edge_Type>::dfs( int _cur, int _father_edgeId){( n; H+ J8 a( ?
stack_[ stack_top ++] = _cur;
: B, F0 G7 D9 B8 P1 F4 E' q+ C9 h low_id[ _cur] = dfs_id[ _cur] = dfs_idCounter ++;$ p4 h' z3 S6 V1 c; u2 x
//--2 s" {. W& k' ?, k! D
for( int nex, edge = graph->Head[ _cur]; ~edge; edge = graph->Next[ edge]){+ r1 ^: b7 i% B1 e5 _ V1 @) R5 p
nex = graph->Vertex[ edge];
) x e& Q/ z1 {* o5 M if( (edge ^ 1) == _father_edgeId){ continue;}, d6 W. q% e& Y8 p7 n
if( -1 == dfs_id[ nex]){
( `' T4 R* @' h9 C& a dfs( nex, edge);! h" B2 Z. t4 h1 Q' k
low_id[ _cur] = min( low_id[ nex], low_id[ _cur]);! y2 T0 ]/ k0 \0 g
} `0 M( C& b+ D& a8 F1 P
else{
% O- E, C0 _" o _2 D low_id[ _cur] = min( dfs_id[ nex], low_id[ _cur]);
6 v; N$ I0 n" X- q& a: Z5 m }
1 @$ D; M! M1 t. y9 x }+ T6 d1 v( g7 E6 }( E7 V
if( low_id[ _cur] == dfs_id[ _cur]){' H& J% g6 H9 }
ebcc_size[ ebcc_count] = 0;' f0 i" q# B7 j. q, e, q' [
while( true){
6 d4 W' R) p0 w" w$ e7 N int c = stack_[ stack_top - 1];: i+ U3 j' L& T4 r4 B; b; p0 U3 _
-- stack_top;
/ y+ k1 @" u4 d) [7 c- E' r$ L ebcc_id[ c] = ebcc_count;- m! A0 M" e5 x0 x
++ ebcc_size[ ebcc_count];% u/ X6 _, O0 b: P7 x
if( c == _cur){ break;}
- Y5 G% \" O* E Q" K ?1 O+ m }
- |; W) g* K. P9 d }/ A; ^+ {% }$ Y ++ ebcc_count;
+ u1 Q" m5 L& S2 c$ R5 w- n9 D }
g; o( P& G! M6 H, x6 P5 Y}
/ @2 { ^2 _9 v6 x//} Tarjan_EBCC-Implementation
7 w ~- t. C' J" b6 r* Q9 {) `. [# P# E- O
SCC有向图强联通分量
$ q" l7 b+ A) V. a# E) z1 a//{ Tarjan_SCC
$ U" S9 e' ^" l5 H. ?6 Xtemplate< class _Weight_Type>, [) ~5 L" P% [$ n/ `5 V" Q
class Tarjan_SCC{; G( Z, e8 W" q. }3 x5 P
public:9 y! _- O2 U6 E2 [
const int * Scc_id;
6 B9 P( F6 r; O9 `" F; d: z const int * Scc_size;: o8 ^6 |& U. q
//-- variable ends
# q, c! ~5 j6 P/ v& e* ^: a8 X Tarjan_SCC( const Graph< _Weight_Type> *);6 ?% P" D, r5 j ? H
void Initialize();
' E7 R9 Q; y: |+ ~) m4 ? int Get_scc_count() const;" M' y5 i+ n6 d1 z+ v( m
const Graph< _Weight_Type> * Build_DAG() const;
* N6 C8 v) }, |8 Z9 O( x/ ?4 ~6 R% O const Graph< _Weight_Type> * Build_DAG_uniqueEdges() const;" ~6 Q, s) J+ k& x
private:
" d _0 n; A# C U6 G const Graph< _Weight_Type> * ptrRef_graph;. c& j& d: O0 R* h, ^
int * ptrNew_queue;; L1 Z/ ~& X$ i+ X
int queue_tail;: g! `9 d0 f$ G8 n7 g
bool * ptrNew_isInQueue;
: J! U6 r \5 F" I M int dfsOrderId_counter;
3 z1 d$ a% m' ?" ~ int * ptrNew_sccId;
4 N9 ?1 t7 X, J! `6 I! X; e int scc_id_counter;9 @+ L! p1 H! V( {( g# ]% K& E
int * ptrNew_sccSize;
, e0 u4 @* v3 `. | //-- variable ends' J3 J! r- _$ h1 }7 r/ C
void dfs( int);" C" {2 J9 p- D2 ]$ h/ G
};
4 @. w9 }! }( o! q//{ Variable-Annotation+ p* @7 T% k6 Y4 S; W" j
// + @Var(Scc_id)( z* w1 P1 r: U6 ]# y' y! `: y
// . `y=Scc_id[x]` where `x` is a point of @Var(ptrRef_graph) and `y` belongs to `[0, @Func(Get_scc_count)-1]`' e) Q5 Z9 {& V% e6 X5 Z
// + @Var(Scc_size) y8 Z7 B% r6 y" W. E$ b
// . `y=Scc_size[x]` where `x` belongs to `[0, @Func(Get_scc_count)-1]`, the sum of `Scc_size[0,1,...]` equals the points-count of @Var(ptrRef_graph)! |4 m$ Z2 e& H+ ]7 |; i
//} Variable-Annotation# f( | L2 q- [# \0 K* O3 d4 q
template< class _Weight_Type> Tarjan_SCC< _Weight_Type>::Tarjan_SCC( const Graph< _Weight_Type> * _graph)' ~, P3 n0 c. r
:5 e3 U8 a1 V5 G1 O8 ]5 r
ptrRef_graph( _graph){ g7 `( N7 X4 C
ptrNew_queue = new int[ ptrRef_graph->Get_pointsCountMaximum()];/ k$ H/ a: R" C0 E9 j- f
ptrNew_isInQueue = new bool[ ptrRef_graph->Get_pointsCountMaximum()];
2 n/ F& B b. ~ ptrNew_sccId = new int[ ptrRef_graph->Get_pointsCountMaximum()];
. `6 K, {4 r" V, @ ptrNew_sccSize = new int[ ptrRef_graph->Get_pointsCountMaximum()];
5 N9 }8 ]& q( g+ u% p; G //--. F( f1 L7 Q% p V4 W* }
Scc_id = ptrNew_sccId;
7 Q$ t9 {% P- f# ]8 L Scc_size = ptrNew_sccSize;$ P/ n2 d9 O; L6 H
}: o. [& v6 [) j" D1 _$ g
template< class _Weight_Type> void Tarjan_SCC< _Weight_Type>::Initialize(){2 u* Q* b6 z0 }+ E* X: O$ E9 V
queue_tail = 0;
9 E* z. \6 G0 _ dfsOrderId_counter = 0;
/ t6 i) H# A; s- a8 o1 Q memset( ptrNew_sccId, -1, sizeof( int) * ptrRef_graph->Get_pointsCount());
6 \; W* T2 Y( U$ n0 E% ~0 a scc_id_counter = 0;
1 w7 k# Y9 R0 j, w7 w3 c+ e for( int i = 0; i < ptrRef_graph->Get_pointsCount(); ++i){8 l& G0 y H+ Q! L, a. ^0 i
if( -1 == ptrNew_sccId[ i]){" \. V; A6 b+ t5 {
dfs( i);0 o" n5 k' m1 a
}1 h# }9 @5 h! ~1 m2 C: ~
}+ x$ x2 j) ^$ p' Z$ L
}
0 M& ~+ e0 T2 f9 |2 x3 f+ ?template< class _Weight_Type> const Graph< _Weight_Type> * Tarjan_SCC< _Weight_Type>::Build_DAG() const{1 N9 p' [* N. h$ _
//< + Make sure @Func(Initialize) has been called
2 j6 A% a# v. R& a' E( V Graph< _Weight_Type> * DAG = new Graph< _Weight_Type>( scc_id_counter, ptrRef_graph->Get_edgesCountMaximum());; }/ V/ h; X; {) r- m8 m* C
DAG->Initialize( scc_id_counter);6 n4 n8 \% A; ~- ^( W3 h, H
for( int a, b, i = 0; i < ptrRef_graph->Get_pointsCount(); ++i){) y" w) q' v# {( s/ |# W9 P
for( int j, z = ptrRef_graph->Head[ i]; ~z; z = ptrRef_graph->Next[ z]){
3 |, c$ q. G. X9 I4 q) s j = ptrRef_graph->Vertex[ z];
, O# n- j x$ O$ e" _7 B1 y% R" T" F a = ptrNew_sccId[ i];
4 B4 l/ m! }# Z9 ~4 N4 @; x b = ptrNew_sccId[ j];
' [9 y" S8 E. G! ]3 v0 y, j$ j if( a != b){ U) h) b+ G/ f T% b
DAG->Add_edge( ptrNew_sccId[ i], ptrNew_sccId[ j], ptrRef_graph->Weight[ z]);6 Q! _0 M) Y- ]( j" F |. D
}
; H$ Y& j; ]. q A }
/ h! x; @- u, Z ~, q0 f/ F# e- m6 W/ c }: T4 \% n( F4 C! f$ G! y
return DAG;
0 @+ O: \4 q6 B1 q% A4 C2 Y7 d}
# v# L$ s( R# a- Ftemplate< class _Weight_Type> const Graph< _Weight_Type> * Tarjan_SCC< _Weight_Type>::Build_DAG_uniqueEdges() const{
) @# n; ]+ ?0 x. [1 X+ s2 L//< + Make sure @Func(Initialize) has been called1 y* k! A; w$ L6 _) P. p
//< + There is at most one edge between any two points in the DAG (i.e., @Ret)) e% o, ^2 t" h8 b$ V7 w% A$ y
unordered_set< long long> hash_edges;
6 J3 M( i; P# w4 n Graph< _Weight_Type> * DAG = new Graph< _Weight_Type>( scc_id_counter, ptrRef_graph->Get_edgesCountMaximum());- { I, p+ Z/ n: O# O' r% S
DAG->Initialize( scc_id_counter);' }8 e4 w3 a) V
for( int a, b, i = 0; i < ptrRef_graph->Get_pointsCount(); ++i){; r6 c+ R/ i3 A
for( int j, z = ptrRef_graph->Head[ i]; ~z; z = ptrRef_graph->Next[ z]){" z' {( r: Z" g& K( C
j = ptrRef_graph->Vertex[ z];/ P9 P, t `3 }" D# H
a = ptrNew_sccId[ i];
8 f+ T' N! z1 @+ z1 a! t6 n b = ptrNew_sccId[ j];( k2 Q: H4 ]8 f1 H* O* g- x7 g2 K
if( a != b){6 r* n5 {: l# G. _- s
long long hash_val = (long long)a * scc_id_counter + b;
( h* d# B$ d" n0 `& d if( hash_edges.find( hash_val) != hash_edges.end()){- K3 z+ z/ q( h8 s$ M h
continue;
& n2 ?( i' z. x) _$ O- {4 }4 x }
- B' W/ X5 g' C3 C hash_edges.insert( hash_val);$ d& X! _& D, y& S7 a$ }) R
DAG->Add_edge( ptrNew_sccId[ i], ptrNew_sccId[ j], ptrRef_graph->Weight[ z]);* c" U* {& R P( ^
}
7 k- y3 L7 P. G+ W2 e3 U }( }- I) Q) J7 _! o$ E, z4 Q
}7 i4 B. ^ Z) x
return DAG;
* O/ H; n- o9 N' b9 X1 \" v}
4 u( V. }6 K) ^, u" ttemplate< class _Weight_Type> void Tarjan_SCC< _Weight_Type>::dfs( int _cur){. @$ C! @6 @2 R, k S" [
ptrNew_queue[ queue_tail ++] = _cur;6 x) f8 }0 b b, Q- ^
ptrNew_isInQueue[ _cur] = true;3 M$ e' X7 F9 a x. S- r- o5 h! m
int current_dfsOrderId = dfsOrderId_counter;
7 p i2 s) o+ L0 S4 W% _ ptrNew_sccId[ _cur] = dfsOrderId_counter ++; T$ c0 k' d- ]# [ @6 i
//--3 W- d5 q: z! F& f8 K4 s. F
for( int nex, i = ptrRef_graph->Head[ _cur]; ~i; i = ptrRef_graph->Next[ i]){
+ g! J, M+ [' T& W$ e nex = ptrRef_graph->Vertex[ i];' t! U+ H8 q, ^4 n9 [" p" h8 A$ `5 [
if( -1 == ptrNew_sccId[ nex]){0 J6 W- G0 Q0 |
dfs( nex);
- d& ]( H W6 y! v8 } }
8 M( _1 S( F2 @2 d$ w# K- U; q if( ptrNew_isInQueue[ nex]){( n9 E, V- |0 C- z
ptrNew_sccId[ _cur] = min( ptrNew_sccId[ nex], ptrNew_sccId[ _cur]);
9 B6 F0 m5 W7 C2 h8 n }
$ A( X: N4 s8 \' W- Y }6 K8 M/ s4 N9 n' i+ @; h2 O
if( ptrNew_sccId[ _cur] == current_dfsOrderId){7 j' b, X" {" i% B
ptrNew_sccSize[ scc_id_counter] = 0;. p+ j/ D& U0 s0 |: i3 \
while( true){
1 G- n8 w% F6 V int c = ptrNew_queue[ queue_tail - 1];
2 x0 I2 ^. c5 h, D ptrNew_isInQueue[ c] = false;2 X2 `% |- e% L" S$ r1 Y5 q" r, t
-- queue_tail;9 L1 `7 @' G" f7 @) L6 u6 h
ptrNew_sccId[ c] = scc_id_counter;
, V# _8 X) i( S# L* m# d# h ++ ptrNew_sccSize[ scc_id_counter];
) q: }: H+ m/ P( [* l if( c == _cur){ break;}
9 Y! v) B- `6 i! o9 f& g, J1 t }
' q; J& A, O1 a" y1 V& ^& C2 B5 E ++ scc_id_counter;
0 b: L' ^- g9 r, @& I8 H }
! o8 H) {8 o- B2 A}, a3 Z. V# m: `! D8 o( V6 Y8 l
//} Tarjan_SCC4 x0 A: s( ]% }% W- i+ f% Y
# a& G: W5 b) d. j差分约束系统,不等式组
% H9 s" ^) F8 C" R/ B, b//{ Minimize_InequalitiesSystem/ T2 _, ?' y! F5 ~2 Y4 J
template < typename _Edge_Type, typename _Distance_Type>1 r p0 z: o. N' {; o" I w
class Minimize_InequalitiesSystem{# T- ]6 h$ A3 |; |
public:
l" K/ z( U* b9 Z7 H const _Distance_Type * Distance;2 _6 c# @ w* e
//-- variable ends
+ R# k1 B6 |1 V7 r+ `+ G Minimize_InequalitiesSystem( const Graph_Weighted< _Edge_Type> * _graph)" z# C. O& H) f$ W, |1 d
:
( \9 R( J8 o$ c9 ]( T5 U ptrRef_graph( _graph){1 C6 C+ n# ^" o; p# P! E) q3 b
ptr_distance = new _Distance_Type[ ptrRef_graph->Get_pointsCountMaximum()];" H5 D4 k U; c9 N$ i
Distance = ptr_distance;
/ X8 g, c- C8 R/ R$ u ptr_isInQueue = new bool[ ptrRef_graph->Get_pointsCountMaximum()];
+ \5 ^, z# c2 X ptr_queue = new int[ ptrRef_graph->Get_pointsCountMaximum() + 1];! C1 y8 H i( A. E( x
points_range = 0;- h" f! B8 n* p" o
ptrNew_pathLength = new int[ ptrRef_graph->Get_pointsCountMaximum()];
3 ~* r1 C0 c! h //--
/ f8 K$ c/ j+ |/ H Initialize();
) e8 d% D- ]* U- Y: m! L4 A! v6 p }. |# f" e/ y3 s, b: N4 H" l7 \
void Initialize(){
' [& p/ Y+ i/ v; \ points_range = ptrRef_graph->Get_pointsCount();
/ W. Z: l7 i, O1 o }3 G Y' o# l# q; B, A, {
bool Work(){) O. ^1 @: m' g7 [. ^3 Z
memset( ptr_distance, 0, sizeof( _Distance_Type) * points_range);
+ x3 W5 m; Q3 `; e8 m% c2 T$ o2 l memset( ptrNew_pathLength, 0, sizeof( int) * points_range);
/ _& G; D! V2 H for( int i = 0; i < points_range; ++i){- d, W0 G8 ?+ v# T8 b
ptr_queue[ i] = i;
; j; s( l+ a' C$ x: V, X) c; i7 ` }8 ~7 r9 w0 } T, q3 a" L6 O
memset( ptr_isInQueue, true, sizeof( bool) * points_range);% ]% J1 _# T; ]1 {% A2 t: T6 \
queue_head = 0;4 E$ x1 n4 z$ r, q7 B& d$ k6 _+ N
queue_tail = points_range;; Z7 S1 \- C) w( S
//--7 ?, [: b) v2 z/ q6 h
int cur, nex, edge;$ W% ]$ C1 T' e0 L) i% V
while( queue_head != queue_tail){
& y& x' h# N/ w5 T- x3 s( V4 t. N cur = ptr_queue[ queue_head ++];1 C( m. l% x' B1 ~8 `5 r z
ptr_isInQueue[ cur] = false;. \3 d j1 l) M8 l
if( queue_head > points_range){ queue_head = 0;}7 [* [+ c/ R+ f+ ?
for( edge = ptrRef_graph->Head[ cur]; ~edge; edge = ptrRef_graph->Next[ edge]){
* x9 C0 C5 ^* s0 h nex = ptrRef_graph->Vertex[ edge];
6 M2 u& Q4 U3 ~+ g( G+ \' n( s6 z$ [ if( ptr_distance[ cur] + ptrRef_graph->Weight[ edge] > ptr_distance[ nex]){
# X0 w- A! ?5 v2 ^ ptrNew_pathLength[ nex] = ptrNew_pathLength[ cur] + 1;
* T {2 C1 [% e- b7 q1 h1 { if( ptrNew_pathLength[ nex] >= points_range){
. {- l8 R! I- @ return false;
- ]: A; f8 F) d0 d% E( L( h/ ~ }4 W7 A' ]. Q9 Q' i! ?
ptr_distance[ nex] = ptr_distance[ cur] + ptrRef_graph->Weight[ edge];2 f$ W8 _: g. x. I7 s- H$ w( m) v
if( false == ptr_isInQueue[ nex]){
k3 ]. c/ W$ p1 ~& n- C7 W0 [ ptr_isInQueue[ nex] = true;; u1 R" ~- C/ a' n) D; r
ptr_queue[ queue_tail ++] = nex;4 L4 G7 |: d+ p0 e8 l9 ^
if( queue_tail > points_range){ queue_tail = 0;}
' r2 p/ Y5 l5 Y* r* m$ c }
- v& s4 l) U( v6 U4 `# O9 A3 A# N+ R }
3 V- z8 ]$ j w' J8 \! a6 r }' E1 A3 _/ J: s* F) i
}& p- E5 R( W& J0 }( q7 U8 z
return true;: z( [5 |2 z4 ~' q: r0 w- e, ?
}
: ~9 P' M8 i) vprivate:) v' g2 O& U0 b* `7 ?4 U4 J7 z2 c3 d
const Graph_Weighted< _Edge_Type> * ptrRef_graph;
6 ?, b9 V1 s- C$ y& A int points_range;
' n! e- i* M; D0 U1 z _Distance_Type * ptr_distance;( n4 H0 s& f" d( W0 x
bool * ptr_isInQueue;; r0 T. {) i$ c6 P8 D" ]8 M' }
int * ptr_queue;
) f* r8 `, \+ k4 x U! g int queue_head, queue_tail;# m, N* }' R- E7 Q3 u0 J
int * ptrNew_pathLength;
( r+ Q- }! }0 O' d6 Z};
* h/ I6 t0 v; O5 I! [& \7 V//} Minimize_InequalitiesSystem
, a/ L3 i) F p: o
X$ l+ s; T) |& i2 LCaution" _3 V0 ] {) t( ?% g
5 P8 e% }2 B, A( a# x G
`+` You should never modify the source-code of @Func( Work), otherwise, it means your algorithm must be erroneous.
/ U5 o/ {% [0 ]* a. C. `; A, t7 C1
( V+ b% R2 F% o9 i3 z2 sAnnotation: r5 i; r, g! ?5 Z$ r( S7 K- \* O
" H) n/ _+ Z6 l. P( V# @
`+` @Func( Work)
+ G7 k+ `7 ^' u( C8 X h* ]! \! J`1` `@Ret = true` means the Inequality-System is Consistent, otherwise it is Inconsistent (No-Solution).6 |( A3 E0 Z& X) _, b( @% f2 w
`2` The effect of this function (if @Ret is true) is calculate the minimal-value for every variable (point) $xi$ Under-The-Condition-Of-All-Varible-Must-Be-`>=0`;
* y1 Z3 h: H, K8 Q/ ^' r7 q`.` In other words, under the premise `all variables xi >= 0`, minimize every variable and also satisfies all relations (i.e., the graph)
* C' H' g+ c0 E6 u2 s! e: G1 B2 I& m( ~! N5 A# e: H; o
`+` @Var( ptrRef_graph)
, z4 y, I; w6 ?! ]4 f`.` A edge `x -> y` with `w` muse always means a inequality `x + w <= y` where `x,y` are both variables and `w` is a constant.2 n2 F0 G7 Q; z( g- R2 @
1 C% e6 q5 a( I3 D2 ]- V. C }
数论. {( e6 h% P9 ]. L+ p* L- j
矩阵乘法0 G! U- l/ l( \( E$ u
//{ MatrixMultiplication-Declaration9 _# G' @6 L+ a5 g" ?8 R; o4 Z- w
template< class _Type, int _MaximumLength>, o9 k+ L8 T, A/ r/ k9 Q
class MatrixMultiplication{/ o, Y6 w. m5 O: B1 e1 q4 B
public:7 J% m0 ~ L3 U7 {/ Q
MatrixMultiplication( _Type);. ~- O! c/ `, m' B
void Initialize( int, _Type (*)[ _MaximumLength], const _Type (*)[ _MaximumLength], const _Type (*)[ _MaximumLength][ _MaximumLength], long long);, g3 d9 g5 n4 Z5 x: M- a
private:7 U8 o" t% w, C2 |
_Type modulus;
) t) A; `( k# U' H int length;
% `& R" v) A: ]6 K7 h$ x6 p# g _Type factor[ _MaximumLength][ _MaximumLength];$ [- A$ _# `, z/ I0 S
_Type answer[ _MaximumLength][ _MaximumLength];, [' I# ~4 [: X4 ~ u2 k
_Type temp[ _MaximumLength][ _MaximumLength];) D& Z! _! V! i. r j ~
//-- variable ends
* t( v- @# K/ ] void matrix_multiplication( _Type (*)[ _MaximumLength][ _MaximumLength], const _Type (*)[ _MaximumLength][ _MaximumLength], const _Type (*)[ _MaximumLength][ _MaximumLength]);
3 R3 [' O2 l, ]6 \& O( @: S};4 a/ o; w& W0 J, j Y; {+ a
//} MatrixMultiplication-Declaration
! Y" J5 e* {' ~& C! T& M3 S2 ]% p" V/ h; \6 K
//{ MatrixMultiplication-Implementation
/ D e$ r* ^4 n- c9 x k8 Itemplate< class _Type, int _MaximumLength> MatrixMultiplication< _Type, _MaximumLength>::MatrixMultiplication( _Type _modulus)
5 w, [4 U5 D- y! B5 M :4 x5 O1 R0 v' K' L% W
modulus( _modulus){3 ~* ]/ ?9 q$ w6 H4 h% `4 P# \& L
}
; n# d. v; D. ?9 utemplate< class _Type, int _MaximumLength> void MatrixMultiplication< _Type, _MaximumLength>::Initialize( int _length, _Type (* _result)[ _MaximumLength], const _Type (* _dp)[ _MaximumLength], const _Type (* _factor)[ _MaximumLength][ _MaximumLength], long long _k){# e% D7 F( T1 B
//<% x5 {( P. z8 o6 O9 q) o
// @Brief
6 G; J5 P+ |$ E6 z2 M// . `result = dp * (factor ^ k)`;
. b" t: f# ^ D9 N// @Warning/ T+ ~ m' E% I, ]
// . Make sure the data of `dp` is `dp[0, ..., _length)`, the data of `_factor` is `[ (0,0) -> (_length-1, _length-1) ]`;, b/ c& I' o2 n o$ B4 @
ASSERT_( _k >= 0);5 q$ {, ]8 @4 r# c7 N- m, T* J3 P' j
ASSERT_( _length <= _MaximumLength);
2 R' v( z, r/ R2 ] //----
5 u- G) T! U2 i5 |) J length = _length;
. j1 b9 L) o0 @% E% I; U //--
5 h4 w( r8 x+ U6 k5 {1 d/ p memset( answer, 0, sizeof( answer));2 A) L; I7 D8 |# a+ E0 a
for( int i = 0; i < length; ++i){
% P$ R& i+ P: A/ L answer[ 0][ i] = (* _dp)[ i] % modulus; if( answer[ 0][ i] < 0){ answer[ 0][ i] += modulus;}
, t D2 n% m! y/ H! D# ^; [ }
, z" Q* l* T; i for( int i = 0; i < length; ++i){
5 t% N! N# M, _) `8 q9 n# J7 u for( int j = 0; j < length; ++j){
) g/ w" g; B9 ]0 x* \0 t, Z0 d factor[ i][ j] = (* _factor)[ i][ j] % modulus; if( factor[ i][ j] < 0){ factor[ i][ j] += modulus;}
6 m9 T# ~. J, e9 Y }
/ _1 `5 _2 X+ ^& B. ?$ i- j# m: B }% P5 K, i5 y+ ]. P: q8 Z6 Z. Q
//--# o/ D2 E# n0 T6 I, {( |
while( _k > 0){3 P4 z e H8 ]+ r& A4 Q
if( _k & 1){, W4 z" m! n- w9 E; t) [
matrix_multiplication( &answer, &answer, &factor);, e9 W6 l2 x! j0 p3 Z% n; J/ n5 W
}
6 J; ~# ?9 H8 G. j- g# X& Z _k >>= 1;0 r( H- C; B: L S$ g7 K! _$ W
matrix_multiplication( &factor, &factor, &factor);
) a; x K, v- A% P' l }
) H3 c; e+ ~2 h8 {: P' R+ u' i( ] //--, p9 u4 d1 {. \0 X8 h0 J
memcpy( _result, answer[ 0], sizeof( _Type) * length); // the address of `_result` equals to the address of its first-element;# ]* ^. r T; k, _( P
}
, O$ T( l$ [2 W5 Ytemplate< class _Type, int _MaximumLength> void MatrixMultiplication< _Type, _MaximumLength>::matrix_multiplication( _Type ( * _result)[ _MaximumLength][ _MaximumLength], const _Type (* _a)[ _MaximumLength][ _MaximumLength], const _Type (* _b)[ _MaximumLength][ _MaximumLength]){
) L4 I+ U( G* V2 Y: M//<& n* r) X. s5 S8 M+ ]
// @Brief
1 d/ P+ d2 W2 W) G D u) s" E// . `result = a * b`;
" f4 `' D4 S& p for( int i = 0; i < length; ++i){( r4 c7 `6 B: S: B+ s& l
for( int j = 0; j < length; ++j){
" a# b0 Y. I8 l //>> Cuz `result` maybe equals to `a/b`, you need store the result to `temp` not `result`;
* U5 g$ I( z! O temp[ i][ j] = 0;
- n+ Z$ u9 R& }7 a5 y; n8 n# K, U for( int z = 0; z < length; ++z){
* z3 ?& x( l& a temp[ i][ j] += (long long)((* _a)[ i][ z]) * (* _b)[ z][ j] % modulus; if( temp[ i][ j] >= modulus){ temp[ i][ j] -= modulus;}% ?; x4 g# Y1 T4 J" ]
}! E2 X9 u9 P. b$ ` b
}
- K6 L: g( P0 [2 B/ s) K: m }
* D$ i5 A) `; [. q% _7 b memcpy( _result, temp, sizeof( temp));$ c( V6 [8 S; g' C6 B* {
}
0 B/ U2 r' O4 }: d) L& w//} MatrixMultiplication-Implementation7 V! i8 u q, ]1 y2 t
0 j: U6 h' p3 `; M" j5 `
@Delimiter; N" H) _% q# o1 y) d
' g; D' b$ e' u$ b& m/ _示例- S# C8 x5 P: B- u- A! }
7 m0 {0 b, t$ I+ `9 Qint Dp[ 4] = {1, 2, 2, 1};
' J+ j+ c; k' k6 U: Hint A[ 4][ 4] = {{0,1,0,0}, {1,1,1,0}, {0,0,1,1}, {0,0,0,1}};
6 B. X+ x# F# A+ CMatrixMultiplication< int, 4> Mat( M);" B; U5 Q/ J$ w: b
Mat.Initialize( 4, &Dp, &Dp, &A, N - 2);
+ z4 p0 q# \% t& w" A# V
; m+ v# ^6 k) {long long ans = (long long)Dp[ 2] * N % M - Dp[ 3];
# f- z+ A) m+ t$ s% Z' Fcout<< ans;1 }% v& j( Q% w( X: S/ y2 R
19 G: y: T% b8 S7 m* L
2
# R b% |2 C& V3 E* Q36 i j+ _! `( z: j1 b
4
4 y3 s4 }0 Q, ?% X2 _- D+ \5
& ] G9 D. N& f/ h( r6 f6 H, ^2 s0 ` J
7
. K4 V, d9 o6 x1 S+ d; p( j4 U中国剩余定理! [8 b0 J# R& d5 ^5 [
朴素 CRT
$ N; H" l1 H3 Y! I//{ CRT-Declaration
: K- m! M, ]& F" \# Q! Ptemplate< class _Type> pair< long long, long long> CRT( int, const pair< _Type, _Type> *);
; b; J7 `) A( m: l//} CRT-Declaration
, X- k; Y3 r* p# C
B: a L7 Q+ P& E% g, g7 W5 q& m//{ CRT-Implementation
" R' T# Q4 w/ | ptemplate< class _Type> pair< long long, long long> CRT( int _n, const pair< _Type, _Type> * _arr){5 p* \0 U5 W2 T3 l( Q+ [, a9 n1 a3 Y
//<
' E) U# @4 b3 {! O// @Brief+ M* `/ z& z- y* U2 N3 i j
// . Solve the system of `n` Congruence-Equations represented by `arr` (i.e., `? = arr[i].first (% arr[i].second)`);
2 A4 B2 {2 f1 R# B// . Once all `arr[?].second` are Pairwise-Coprime, this system must be Solvable (and Infinite-Solutions);
( G: s" e }" ^8 `" P/ U- ~// . @Define( `(a,m)` = @Return), `a` must in the range [0, m), and the Solutons are $a + kk * m, \forall kk \in \Z$;
: s; x5 x5 T ?$ F8 b }$ i// @Warning
- t9 R: {( Z+ l! X) F, R$ ]// . Make sure all `arr[?].second` must be Pairwise-Coprime;
+ k1 P" q. P% i+ j1 }- `+ s5 U// . Make sure the Product of all `arr[?].second` in the range `long long`;# k* W+ n1 B. u; N" A$ w' h
// @TimeCost
- ~# X6 j3 p/ F! H" g2 W// . $n * 60$;0 I1 n5 R6 u A: d7 }. h
long long M = 1;
- p- `- E& H7 w, b* s/ S) d# n for( int i = 0; i < _n; ++i){
# P9 U) T$ m1 J0 Q- | ASSERT_( _arr[ i].second >= 1);4 A7 E4 j4 ]$ I' c
M *= _arr[ i].second;
* F# u4 N- Z- s1 m- p6 v }
( Y* i8 I) j9 e* i3 C" s long long answer = 0;: Y: ~6 o; X6 s7 A+ m! c6 H
for( int i = 0; i < _n; ++i){9 H* a) ]1 z7 Z: e! C* `: s# X
_Type a = _arr[ i].first % _arr[ i].second; if( a < 0){ a += _arr[ i].second;}8 u0 J2 c+ K* K" w3 L
long long m = M / _arr[ i].second;
$ ?" k" d0 y4 A$ Z% [! _1 O5 L) Y pair< bool, pair< _Type, _Type> > ret = LCE_BezoutE< long long>( m, 1, _arr[ i].second); // m * `ret.second` = 1 (% _arr[ i].second);$ w2 @0 a o3 t* I$ i
ASSERT_( ret.first); // All `arr.second` are not Pairwise-Coprime which rebels the Premise-Of-This-Algorithm (See @Warning);
0 C: x8 g- w: f" i answer = (answer + (long long)a * m % M * ret.second.first % M) % M;
$ n h3 S- ]4 t; `: X }, i& j9 F$ H( u, ?
return {answer, M};
6 w8 ~; c* p( N( b+ [+ X}
1 ~, {0 [# c( @//} CRT-Implementation$ q* c# P& N/ P/ S7 l+ w5 X. N
) X( t" i T: n0 w拓展 CRT_EX
7 O0 f2 W0 }* I( ?5 [//{ CRT_EX-Declatation8 V4 e- R! J$ J2 L
template< class _Type> pair< bool, pair< long long, long long> > CRT_EX( int, const pair< _Type, _Type> *);
, G' T# m( V/ M( P, W+ P7 Y% G' r/ u//} CRT_EX-Declatation
. e( k; P f7 r+ {: W# G( ^
z# W# i# {- r* W//{ CRT_EX-Implementation
0 _1 j7 O; g- ^1 p# T. u- Ctemplate< class _Type> pair< bool, pair< long long, long long> > CRT_EX( int _n, const pair< _Type, _Type> * _arr){
: z9 b/ M! J2 [# h: N//<) E' _$ b2 `. P D; |
// @Brief
9 f5 Q' z6 {' w% S Z// . Solve the system of `n` Congruence-Equations represented by `arr` (i.e., `? = arr[i].first (% arr[i].second)`);$ M0 d4 C4 J' o% @; n1 J) v6 i- I
// . @Define( `(r1, (r2,r3))` = @Return);- ~& h5 W$ m2 T0 K6 d
// 0( r1=false): There is No-Solution;# b7 N5 w, J" P3 w; T9 m4 B7 K1 f" u |
// 1( ELSE): The Solutons are `r2 + kk * r3, $\forall kk \in \Z$`, and `r2` must in the range [0, r3);
k4 `; A u3 t! m$ o( U// . All `arr[?].second` maybe not Pairwise-Coprime (which differs from `CRT`);
' P& N, V" q% e+ i) j5 Q// @Warning, D# O" b( V6 h6 i. }
// . Make sure the LCM (Least-Common-Multiple) of all `arr[?].second` in the range `long long`;
c% n; ^0 A+ [( ?5 D// @TimeCost
2 Y4 s P9 D. L( }1 P// . $n * 60$;; c4 F' y6 \- [. C# ~6 F& _
pair< bool, pair< long long, long long> > answer;
9 ?+ ^) U$ E. `0 r+ ?4 W long long A, M;- Q6 y9 q7 H1 n7 y# L
for( int i = 0; i < _n; ++i){
. r) [6 S% G% o9 c( o+ ]. L" l% M _Type a = _arr[ i].first;
; S+ w6 u6 k# K5 W a %= _arr[ i].second; if( a < 0){ a += _arr[ i].second;}+ g1 V' p; `9 J- C7 u- |
//--
3 x- n$ o- r4 @3 v( V! m if( i == 0){
# u* P# e) h' c) @: R( |4 s0 ^9 B A = a, M = _arr[ i].second;
0 A/ u6 P. ~6 a continue;) n7 }3 X( c; R9 ?" M+ S5 u
}6 l/ ?! y. i% A9 R" C9 q7 A& h
pair< bool, pair< _Type, _Type> > ret = LCE_BezoutE< long long>( M, a - A, _arr[ i].second);
9 v& P) ]- m& ~! M8 w4 G' r if( false == ret.first){7 ?) j& `5 J5 S p$ I0 ~* b
answer.first = false;
/ v r' m3 q. V) _- {6 }' y2 n6 i6 d return answer;
& e3 B4 A p& s" z, p }
$ Y9 S! F: C& ~ _Type gcd = _arr[ i].second / ret.second.second; if( gcd < 0){ gcd = -gcd;} // The GCD of `M` and `_arr[i].second`;
+ {; A; M8 Q$ P0 S$ o long long new_M = M / gcd * _arr[ i].second; // LCM
7 @0 k' `4 J; e5 A/ ] A = (A + ret.second.first * M % new_M) % new_M;
( M3 e& r& H# y% U6 S# R M = new_M;
U% n r( T. a }) V9 y* ~/ f# f5 G/ q6 N0 k
answer.first = true;- n8 I- t( ~8 F, j( H3 l
answer.second.first = A;( E/ F6 ^9 C6 ]4 ^. W
answer.second.second = M;* b8 r2 ]+ s6 H3 D( c" o# C0 w7 m- z
return answer;2 _( H& k' A% j, o. z3 _
}4 A* e1 h7 Q3 e- w8 E1 T
//} CRT_EX-Implementation0 A R' ^) T* C8 @! P; K2 s, e
17 A. j1 Z1 E2 g* g6 N: W6 b
裴蜀方程 BezoutE6 Z9 u! ?3 c1 K/ _) ^( [9 j8 G& X
//{ BezoutE-Declaration' V- o& r* ?5 m7 w6 }# g8 F' S2 g
template< class _Type> pair< bool, pair< pair< long long, _Type>, pair< long long, _Type> > > BezoutE( _Type _a, _Type _b, _Type _c);
3 I+ S& e' ^% c: Y* B1 N//} BezoutE-Declaration. V P% f& o0 U8 l2 N5 t
/ l; Y6 U: M1 y; P9 `% [4 l) {/ m7 k//{ BezoutE-Implementation
" F3 H! G' \; L% |2 N! X' [template< class _Type> pair< _Type, pair< long long, long long> > BezoutE_extendedGCD( _Type _a, _Type _b){
7 _; `0 w, }4 E! f" W//<$ d. e7 x/ z$ e* |8 w/ @; a
// @Private
) r) a' C3 I# l# s// @Warning
0 Z E4 b- }, {8 g7 [9 v& Z// . Make sure `a,b >= 0`, Not-Both-Be-`0`;: O/ S# {+ B2 y/ x7 c# t
if( _b == 0){
: ~4 a; n9 Z5 U* ~0 G return {_a, {1, 0}};
1 J8 @3 @( I) F }
5 f7 E! |; M- v7 q; _2 _ auto pre = BezoutE_extendedGCD( _b, _a % _b);9 h' p3 k( f* N7 ?5 [ ~
auto xp = pre.second.first;9 S( M# D$ m H1 |
auto yp = pre.second.second;: E& J3 G$ J; A6 Q0 z$ o, {
return {pre.first, {yp, xp - yp * ( _a / _b)}};
$ e6 f, p7 O) b2 i- c9 \3 A q};( b" `* }; @( q5 g5 ~6 J7 j- [
template< class _Type> pair< bool, pair< pair< long long, _Type>, pair< long long, _Type> > > BezoutE( _Type _a, _Type _b, _Type _c){
2 F6 s) G5 H# z5 |//<3 I) g9 A3 D. x/ T+ O% Z. s6 `1 m+ v
// @Brief
8 _; d+ W' U7 L9 @4 w+ `9 B: ]* n// . Solve the equation `xx * a + yy * b = c`, @Define( `(r1, ((a1,m1), (a2,m2)))` = @Return)`;
7 Z0 q: G( H0 s5 @! i// 0( r1=false): There is no Solution;$ X4 \! I! x5 O* _; a
// 1( ELSE): The General-Solutions are `(a1 + k * m1, a2 - k * m2) $\forall k \in \Z$`;
1 _+ a' O, e( f9 r$ F9 e0 {: ~// @TimeCost
3 G2 e( x6 l( E- c. ~9 T& p// . $\ln(a)$;
! Y: A E4 Z0 l3 [. z2 M// @Warning+ W5 E( U( X: i/ B
// . Make sure `a != 0`, `b != 0`;# `& Z1 [* |! Q2 {" C* |
ASSERT_( (_a != 0) && (_b != 0));
' k+ ?( f4 M& B6 P8 v2 p+ I$ \7 _ pair< bool, pair< pair< long long, _Type>, pair< long long, _Type> > > answer;! n/ X: h8 L6 G% ^6 S
bool neg_a = false, neg_b = false;
3 g7 Z/ }4 F" [; R if( _a < 0){ neg_a = true; _a = -_a;} // `x * a + y * b = c` -> `(-x) * (-a) + y * b = c`;
6 w4 x# E# y3 ^/ C+ S( b if( _b < 0){ neg_b = true; _b = -_b;} // `x * a + y * b = c` -> `x * a + (-y) * (-b) = c`;. p% q7 q! g A0 G% H( c3 r
//--/ V0 `* ^: c- m
pair< _Type, pair< long long, long long> > ret = BezoutE_extendedGCD( _a, _b);
. b9 \7 L1 W2 v5 c# o. I8 [: }& }7 g' m if( _c % ret.first != 0){6 `0 a, e, n$ E: q/ E
answer.first = false;
" ?; m; ?5 L4 ^ return answer;
k- s* u3 a& x- r5 A }
! I/ |5 G; n. o! |6 z6 T( n answer.first = true;
; a4 Q E& V) _ answer.second.first.first = ret.second.first * (_c / ret.first);
/ I) L) k, Z4 C2 ], a! d3 S) F1 c9 ~ answer.second.first.second = _b / ret.first;
! N; t0 M) `4 _$ L3 L' c3 l5 X3 @ answer.second.second.first = ret.second.second * (_c / ret.first);8 d! _! y* v. S4 S* J% o
answer.second.second.second = _a / ret.first;
* W3 K9 N8 R& R if( neg_a){ answer.second.first.first = -answer.second.first.first;}
' v' y; j6 B' n$ i. ]/ R8 E if( neg_b){ answer.second.second.first = -answer.second.second.first;}5 {) v7 R) I# |
return answer;8 u! j+ Q& ]: A3 Y# O
}
) @9 g& M9 s0 I//} BezoutE-Implementation9 x, D& L8 ~8 X, k; l
: ^ I8 n9 M1 I5 r
线性同余方程 LCE
% I8 P2 i8 K: M# p1 Z& |8 @4 F" k裴蜀方程法 LCE_BezoutE
( B2 @, ^, r2 z! r# n1 k//{ LCE_BezoutE-Declaration
( [7 h& h$ G' x! t5 btemplate< class _Type> pair< bool, pair< _Type, _Type> > LCE_BezoutE( _Type _a, _Type _b, _Type _mod);2 C) V2 O0 {4 u. C
//} LCE_BezoutE-Declaration
( C2 t+ H; c( }* b
7 v# X6 R/ R9 Y/ Z1 z7 t//{ LCE_BezoutE-Implementation( N, h6 g9 \/ T$ V, P1 {. F9 Y
template< class _Type> pair< bool, pair< _Type, _Type> > LCE_BezoutE( _Type _a, _Type _b, _Type _mod){4 s& r9 f$ A# T m- @( M
//<2 n1 D1 m% o7 c, p
// @Brief
. u$ u+ }! {; E" M4 d// . Solve the Congruen-Equation `a * ? = b (% mod)` where `?` is @Return; @Define( `(r1, (a1,m1))` = @Return);+ k* d& ?$ ^( g! A, P; z
// 0( r1=false): There is No-Solution;
" `* \- o/ s, D" \1 z' p// 1( ELSE): The General-Solutions are `a1 + k * m1, $\forall k \in \Z$`, and `a1` always in the range [0, m);: {8 I5 P* W- |0 y/ `% ?7 `" }
// @TimeCost
! a4 r& ^9 |1 \( L2 b// . $\ln(_a)$;
7 _2 i% }6 i: k: G! ~ ASSERT_( _mod >= 1);1 u( v ^ N2 A' Y# y, y
pair< bool, pair< _Type, _Type> > answer;5 c/ t& P/ G9 U7 r8 i
_a %= _mod; if( _a < 0){ _a += _mod;}" S& ~7 n% a5 c ]
_b %= _mod; if( _b < 0){ _b += _mod;}9 z# v& _5 T2 K. j( S
if( _a == 0){. R- X9 M2 T, x- K: {
if( _b == 0){( W& ~- |& |3 |8 g. j5 G* i: x1 H- ^
answer.first = true; U! e3 d, p1 o& I& }5 c7 [
answer.second.first = 0;9 ^7 h8 j% J( c- k. o! {
answer.second.second = 1;
8 }( s1 \. i3 ] return answer;
/ M( q- B' e& \) N; W- D }
2 N; N( c6 ^" o9 W$ V else{
4 O2 r% X& l2 l: M: B answer.first = false;
9 d" w8 x2 r5 U9 I return answer;) e" F0 k) ^+ v" Z& {
}
( M d; j H) [% ]5 d5 E8 _ }
! |3 n+ r$ T- P& m _Type gcd = GCD< _Type>( _a, _mod);
; G/ \8 k5 Z' y9 a+ ]' b3 f( J5 |. } pair< bool, pair< pair< long long, _Type>, pair< long long, _Type> > > ret = BezoutE< _Type>( _a, _mod, gcd);+ J( M+ T% V8 W
ASSERT_( ret.first);: m2 X. Q4 S4 p# l8 T8 O7 p
if( _b % gcd != 0){
+ O( e! V. D! s4 f0 w. b& C$ E answer.first = false;
+ U2 \1 b& [4 d% K% J) B! `+ K6 ` return answer;
. J- o8 O; g6 g4 M }5 z) _5 {9 l8 _
answer.second.second = _mod / gcd;
0 }5 k4 ?3 k5 J8 {) @# q answer.second.first = Binary_Multiplication< _Type>( ret.second.first.first, _b / gcd, answer.second.second);
# g1 O9 `# K) z; Z answer.first = true;
+ i F- M, V: w$ z. ] return answer;1 d, S( `% \" U# F
}
. g7 X) C4 S8 K% [) T" z: I7 z- H8 B//} LCE_BezoutE-Implementation
+ z* w7 S3 X8 [, Y. B# G/ A4 l% F1 d# }2 I5 [3 B
高斯消元线性方程组
$ t; ~: ~5 N4 N) d) I//{ Gaussian elimination
4 O! O" w3 P. B2 S6 W, mdouble Aug[ 105][ 105]; //< @Abbr( augmented matrix)
5 A0 @# U" V+ u- g: S/ W/ uint Gaussian_elimination( int _m, int _n){: C5 Z- M' C6 A5 a6 I
//< @Par( _m): the number of equations
0 p3 {( A* g( a//< @Par( _n): the number of variables$ W( e; c/ Z2 ~0 V
//< @Return: (0 is unique solution), (1 is infinitely many), (-1 is no solution)6 e( Q# p) t* q F; g# r' d3 }
int rank = 0;4 n4 q8 i6 H/ F4 t! A K4 Q* O' F5 V
for( int col = 0; ( col < _n) && ( rank < _m); ++col){
$ q6 @- ]2 z) a# Y& w4 K) X& F& d- N int max_row = rank;
" K A: _0 M+ Q; I- T for( int row = rank + 1; row < _m; ++row){
) g) E. |- x# I5 K& Y3 o if( fabs( Aug[ row][ col]) > fabs( Aug[ max_row][ col])){
% d5 C! \5 q2 b" G$ K max_row = row;
' w- H+ }1 @! n% G6 e: M }
[0 }; }+ |' T4 j H8 ~* q }0 d: x( {# A' L- Q$ m2 F: q
if( 0 == Db_cmp( fabs( Aug[ max_row][ col]), 0, Epsilon)){
9 I1 r, y; c: ^2 T2 ] //* either no solution, or infinitely many.* u* Q/ R8 J ?# v
continue;: L' M. F$ S* s; c; g3 a
}6 o! Y4 Y- o+ A, ^. p+ e
//{ swap two rows9 d, u% A% `. I6 a% ^
for( int c = 0; c < _n + 1; ++c){
7 P& t/ Z, a) Y! G swap( Aug[ max_row][ c], Aug[ rank][ c]);) B+ |( ~2 r3 Y$ k4 b" i2 p
}
* O" X3 w' R* c5 r- H3 @9 K //}
& p- r* T$ X+ K) X2 ? //{ make current pivot to `1`/ e o3 u7 \ g/ f: Y" R$ s! P
for( int c = _n; c > col; --c){
, X, p4 t6 r5 o% W( M Aug[ rank][ c] /= Aug[ rank][ col];
& G3 R. N! M/ W# a5 K; _7 h }) B0 _; f, ~, y/ ]
Aug[ rank][ col] = 1;
$ f6 ]3 Y7 A/ s- ]) L //}
) Q: E! t! n6 @$ v) @/ Z" G; `7 j //{ make all rows below current pivot in the same column to `0`
) F4 _2 b, y& L9 f# x0 o0 |* e for( int r = rank + 1; r < _m; ++r){
1 x1 l: [6 P }9 O+ u: y if( 0 == Db_cmp( fabs( Aug[ r][ col]), 0, Epsilon)){6 E7 [5 u0 r1 d
continue;
' o1 e. b# R0 o3 \2 n }5 @" ^! N" w' o5 A L% V+ E2 p% O
for( int c = _n; c > col; --c){0 @$ I* z" l3 Q* B; c
Aug[ r][ c] -= Aug[ r][ col] * Aug[ rank][ c];
2 |: o9 r0 z$ A* ` }, |# I M$ Q+ T4 s5 B1 x! d& \# H1 C1 F# ]
Aug[ r][ col] = 0;
" x( m' J, [+ i9 C( K1 `5 [* w }
# u/ \0 Z. j3 z: |) | ++ rank;
2 G* A4 z0 |7 U) }* `+ Y }
* q) ^6 `9 T9 W6 Y! s //--
( ^ E$ \& G ] X- C: H2 B. i for( int r = rank; r < _m; ++r){9 J/ L+ l) E5 }. E
if( 0 != Db_cmp( Aug[ r][ _n], 0, Epsilon)){
, @/ x9 e3 N3 T return -1;
! v; ^" K. b+ w4 g. D: } }8 S% E. U2 N7 Q& Y+ n. b& E+ D; X2 Y
}
0 H u: Y# ^) l if( rank != n){9 q5 i' P* N7 B8 U! _/ j
return 1;
1 C7 x/ i {) v. g }( ]9 F# |# ^2 k* y3 w
//> the upper-left `_n * _n` submatrix of `Aug` is a identity-matrix
, C. H5 B3 ]6 G' X+ ? for( int r = rank - 1; r > 0; --r){
; C: ?5 y1 w: _9 Q) o- ` for( int rr = 0; rr < r; ++rr){" ?0 \; ^9 {' X
if( 0 == Db_cmp( Aug[ rr][ r], 0, Epsilon)){
& [5 j) q+ W0 h _2 q- E) J% {- ] continue;6 p0 a J( Z% n$ W# A1 R9 {
}8 k0 ]0 i: u7 h% @( i5 U
Aug[ rr][ _n] -= Aug[ rr][ r] * Aug[ r][ _n];
6 k* ~& T8 g `- K" [4 W2 [# a# e5 |9 L Aug[ rr][ r] = 0;
3 Z" i% _3 P6 M- O. f T }
) C/ q; \2 [! P4 c: Q }
0 f; \5 D' h+ R; {. t return 0;7 f9 S. v( I& e/ s8 e+ ?
}
/ K3 C+ f+ t5 B* `; b. G7 |//} Gaussian elimination
, b$ l- H! X, M4 n" e9 s" _! K0 ?; q. \
+ b& f4 u, l; d$ v |
|