|
|
算法 {算法代码模板,算法模板编写规范}" H9 g$ h* X, z
supimoTemplate.cpp
+ w0 f* {5 U& Z7 Q/ J% P1 N, N代码1 q+ {8 t( d! x+ T; b1 o/ P
#define ___SUPIMOenvir_( T% r4 |- s% M# y, H' t" m# I
9 ?5 \$ U# f4 m) H) k9 l7 x
#include <bits/stdc++.h>
1 `- j; [$ }: Q1 ?. Yusing namespace ::std;
' E/ U7 R# n x. T ~! P5 k
0 I# a& N7 ~. g! u% I" S4 A#ifdef ___SUPIMOenvir_7 ^( q) T* i) G' P' g, J C! K
#include "supimoDebug.hpp"
3 ~3 J2 u6 K) |$ W' r#else" c, \4 J( Q+ J6 I$ f( [6 M2 V; ]% w1 I W
#define TOstringITEMS_( ...) ""* q" }! [: ?4 x7 b9 w7 L
#define DE_( ...)/ ^2 k( m: a1 g" ~
#define ASSERTcustom_( _op, ...) assert(_op)
8 D) _0 b6 q; B0 W2 {1 e2 \ #define ASSERTsystem_( _op, ...) assert(_op)
3 {% w% R s# ]! q: M* S- {#endif- `! U) j- }' S2 I) k
$ ^5 P. v3 h: N' @2 V#define ASSERTregion_( ...) __VA_ARGS__+ _5 B$ i2 V; e2 j* s [
#define ASSERTsentence_( ...)3 l( l- }1 F1 Y; ~* [3 H8 k, s% \
#define EXIT_ std::cerr<< "\nExit(2267): Line("<< __LINE__<< ")\n"; std::exit(2267);( i2 O' e& t, C. M. y) L. U
#define EXITcounter_( _max) { static int cont = 0; ++ cont; if( cont == _max){ string str = "Exit_Counter(" + std::to_string(_max) + ")"; DE_(str); EXIT_;}}+ S3 }) v- T1 m# {% p7 c) }
#define FOR_( _i, _l, _r) for( int _i=int(_l); _i<=int(_r); ++_i)2 B' e. K2 [2 [$ o8 Y$ I
#define FORrev_( _i, _l, _r) for( int _i=int(_l); _i>=int(_r); --_i)7 w% n! y( u1 r( B* ]3 _
# ^. _, n* m- e6 ^: m$ @# fusing Int64_ = long long; d& t* F! a2 U% P; c
) B. h8 P- _/ M: L4 w
1 [9 }6 z& ?; O5 m; i" C, v
void ___Solve_oneTest(){( [- n- H+ ^8 a& j
}2 w/ E4 G- K8 ~) h
void ___GlobalInitialze(){% A0 I4 c) j! Q+ j. P# ^( r, r
}
# W; w: a% A/ P d1 J1 U" D2 [# X; Uint main(){+ ?9 A! Y4 b. L F, n; m) u+ U
std::ios::sync_with_stdio(0); std::cin.tie(0);
& U, B, {, H2 ^9 @! H std::cerr.setf( std::ios::fixed); std::cerr.precision( 9);
* W/ V! ~6 \3 u8 Y2 K std::cout.setf( std::ios::fixed); std::cout.precision( 9);4 ?; r) E5 |- ~
: u9 c9 v1 z: @/ w7 Z auto ___Solve = [](){ // Problem-Input
, U. J5 w/ d0 j1 y constexpr char MODEisSINGLE = 1;! T& M/ ]) X6 R% c. n r" B' }0 p" W
int testsCount;9 s4 i& z- J2 b* I/ b V/ z1 D+ x6 K0 G
if( MODEisSINGLE){ testsCount = 1;} else{ cin>> testsCount;}, c; R# j% x& m, n
for( int id = 0; id < testsCount; ++id){, I7 r2 L6 Z; L6 m& S
if( id == 0){ ___GlobalInitialze();}
$ Z% S; N) ~1 Q7 c ___Solve_oneTest();
* {4 o' l8 Z, v2 d0 B" _ }% G1 k* V' p% H. @
};: A- x4 x; A, T o2 L
#ifdef ___SUPIMOenvir_+ T5 h& t8 }3 K# U6 c# W& y
while( 1){
+ z4 X# O g1 a5 @: }7 q7 ]! Q std::string flag; std::cin>> flag; ASSERTsystem_( flag.substr( 0, 10) == "#___Input[", flag);' t6 u/ D4 q/ p+ T: {- N' ?
flag.replace( 4, 2, "Out");$ ^7 j$ K7 y/ A7 ~& ^; p- T
std::cout<< " "<< flag<< "\n"; std::cerr<< " "<< flag<< "\n";/ W% x% a; P* g* a8 z
if( flag == "#___Output[-1]#"){ break;}# F% I/ |0 o0 E. t% l0 K0 U
// int timeStart = std::clock();$ Z' z; k6 A. E/ K' t( z/ q/ \7 q
___Solve();
% Z8 _1 B: z2 O) }1 G std::cout<< "\n"; std::cerr<< "\n";7 _8 S# g) K: H a) i
// std::cout<< "TimeElapsed: "<< std::clock() - timeStart<< "\n";9 w) G. A. B( Q! C& D9 m$ ?
}
! q( ~, C/ w2 y) K) K#else( N5 ]* M1 `! D$ G5 V/ o
___Solve();6 p% s/ m& `. C# O8 Z/ n7 \( w+ c8 h
#endif
0 n. G6 L, J: U- c( v
" J+ [2 H1 [$ F, f. R return 0;
4 `' Z0 m- n* }; ?6 g+ A, |- S7 s}
! x: X* j0 |' a. L. s1$ \1 [' K, A) w1 j
2# @6 n, ^, m' V
3
( J0 _" R5 l3 `0 W: E$ R, A( o41 j% z# S( D" H" ]
5
' H) C4 `2 U" \ n- z( {61 w8 Z$ a/ k" q6 P, K
7& ~' n- w1 M% T) c
8, A% o6 @/ l6 w% n2 Q6 P
91 ?4 b0 F5 P" g; [1 L- |
10
' C# @; \; o/ q+ U11
$ ^" v8 Q/ I* H' K' d" Q8 [12
: }( k2 j5 A4 }# M13. I1 }6 `# q# x- g
14
( ^+ |" D( a9 R8 h15
; i- v- v; H/ ^1 {. n161 H9 q4 F" t& Z# h
179 U8 S4 _" X6 C9 c% d3 i9 o
18 x! ]7 P1 l) X( v6 M7 [
19& b9 l# R2 h0 J. q
206 h+ Z$ K1 y+ V- G/ y7 x
21, G/ f/ d6 J: ^0 M
22
' Q/ j, |! m# _* O( W5 a7 q23
/ S" D; ?) N- Y8 J243 V# ^1 R" N4 H' z7 q
25. D8 ?7 E$ X' `& v
26
w; Z+ f& h/ O( `& I$ T27
& F0 n9 o3 r9 w- W3 p( ~8 E28
& q' f1 r, X P# m1 a' L; @297 }5 Y! X8 p$ m! T8 }
30
6 }: M0 e0 l$ b6 w; `31
9 }6 t* h) m% L4 @/ i- s32
1 |; F+ O- i" A& D4 {33
2 v" ~) U) G2 [; o344 Q" ]1 Y9 {. Z
35' o F5 v4 W+ @$ @; M2 r) N
36% ^: U4 n+ C. n9 Y h4 t9 N
37
" T& k: j |/ B) x38
% [* e/ y* ]. l! G. h391 {- |( E [1 M5 M e" b
40. m7 y) x8 V. E, F7 D
412 c" B# E: |' l) N+ S
42
$ E$ b( L; `. O43
( E) Z. l( N4 j I; Z+ i442 z9 H4 G& z- w0 G
450 e! h* d- C8 n2 S2 U* ]
469 a6 |( @$ c" Y2 B* E9 M
47
3 C! @+ S% j3 k$ e9 a Z48: E9 Y8 E; U2 @6 `1 k3 h
491 [8 ^3 w6 o1 O: M
50
3 Z3 u- W" E9 I+ P. \ k51
) c2 m7 I. M: M# A( r; E* \- v5 ]52/ D. `6 V# b- N7 T( s0 M# q" E3 e' B6 F
53- I8 i: L- g+ v8 M) F. s
54
! W, w0 N0 X2 ?5 w8 \55) D& i& a7 z9 y1 m# N! p, U
56
& t4 Q7 _& p: e) s! p3 k0 @8 D$ _57
) o6 _9 q5 q$ e+ Q6 C58
- k8 p+ O+ u; K0 d [59
1 C. `! T6 @6 xsupimoDebug.hpp
$ o6 c4 A. o. j/ y代码4 m3 p- h* q, J
#include <bits/stdc++.h>
+ r7 Q! ^2 i* ], C, Y& P3 z ]/ C7 F+ l+ X/ o* m( G. P+ c( t
#define VARSandLOCATION_( ...) std::string(std::string("{File: ")+ __FILE__+ ", Line: "+ std::to_string(__LINE__)+ ", VarName: ["+ #__VA_ARGS__+ "]}")
6 B# I3 `1 x5 r0 X! I2 t9 D# `5 F#define TOstringITEMS_( ...) ___DEBUG_::ToString_Items( __VA_ARGS__)
9 h5 \2 f/ r1 F; [# p. Z! w#define DE_( ...) std::cerr<< TOstringITEMS_( __VA_ARGS__)<< " "<< VARSandLOCATION_(__VA__ARGS__)<< "\n"2 U8 Q1 K& P' k
#define ASSERTcustom_( _op, ...) if( !bool(_op)){ std::cerr<<"Assertion_Failed(Custom): ["<< #_op<< "] {Hint: ["<< TOstringITEMS_( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< "); Line: "<< __LINE__<< "}"; std::exit(2267);}. w; o/ A+ `: D1 T
#define ASSERTsystem_( _op, ...) if( !bool(_op)){ std::cerr<<"Assertion_Failed(System): ["<< #_op<< "] {Hint: ["<< TOstringITEMS_( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< "); Line: "<< __LINE__<< "}"; std::exit(2267);}
5 V; N& W$ K0 P( b3 w% z1 i. A& D; A; C3 ]# s7 O; ]) P1 ]* X* Y
namespace ___DEBUG_ {
" B, m4 s8 ~6 ^1 x4 P0 _ //>> 所谓`Container`是指 可以通过`for( auto i : S)`来进行遍历的;0 ^+ Z" d( {0 h3 t
template< class _t> struct __IsContainer_Unwrap : std::false_type{};1 A+ z0 k0 _8 u& l4 b' x% q
template< class _t> struct __IsContainer_Unwrap<std::vector<_t> > : std::true_type{};3 Z4 F- N2 \5 } R' ^9 O
template< class _t> struct __IsContainer_Unwrap<std::set<_t> > : std::true_type{};& x1 s: Z6 d2 b1 `
template< class _t> struct __IsContainer_Unwrap<std::unordered_set<_t> > : std::true_type{};1 {% z& v& q' n, q; |% H. y
template< class _t> struct __IsContainer_Unwrap<std::multiset<_t> > : std::true_type{};
0 Y& r$ L/ ]! F template< class _t> struct __IsContainer_Unwrap<std::unordered_multiset<_t> > : std::true_type{};3 S5 g" Q* j/ ~( _. \
template< class _t0, class _t1> struct __IsContainer_Unwrap<std::map<_t0,_t1> > : std::true_type{};, D) M& X# B2 t' ^3 m
template< class _t0, class _t1> struct __IsContainer_Unwrap<std::unordered_map<_t0,_t1> > : std::true_type{};
; U: x$ {0 m, T$ {5 ? template< class _t0, int _t1> struct __IsContainer_Unwrap< _t0[_t1] > : std::true_type{};
! E" f" q& F1 d% H template< int _t1> struct __IsContainer_Unwrap< char[_t1] > : std::false_type{}; // 特判, 字符串常量"..."不属于容器;8 X6 W8 e" j! C8 P
template< class _t> struct IsContainer : __IsContainer_Unwrap<std::remove_const_t<std::remove_reference_t<_t> > >{}; // 不能用`decay` 否则`T[N]`就退化为`T*`了;
+ c3 b' n* k) @% x% L: t! h4 F7 `5 J7 l
template< class _t> struct __IsPair_Unwrap : std::false_type{};
+ {- O( p3 t) b! i' U; J/ Q. R0 j; y template< class _t0, class _t1> struct __IsPair_Unwrap< std::pair<_t0,_t1> > : std::true_type{};
4 L+ Q, w6 @8 g, G" p template< class _T> struct IsPair : __IsPair_Unwrap< std::decay_t<_T> >{};
5 i ~+ x0 G: X2 I) A
: c3 L& l4 c/ V5 i* @ template< class _t> struct __IsStack_Unwrap : std::false_type{};
; n" \: _1 b: ~1 K template< class _t> struct __IsStack_Unwrap< std::stack<_t> > : std::true_type{};
+ _1 i% H0 l$ a template< class _T> struct IsStack : __IsStack_Unwrap< std::decay_t<_T> >{};6 r8 x# X$ M% X/ e. Y
N' q+ \1 J9 U. i" J template< class _t> struct __IsQueue_Unwrap : std::false_type{};
- D( O# C h: @: q- u% z template< class _t> struct __IsQueue_Unwrap< std::queue<_t> > : std::true_type{};
: P$ _3 w' k% X template< class _T> struct IsQueue : __IsQueue_Unwrap< std::decay_t<_T> >{};! U; `6 R0 S2 E( M" u2 Q0 r
2 N9 Y7 r; B) f- F
template< class _t> struct __IsDeque_Unwrap : std::false_type{};
' t3 W0 t% F2 O- x7 H template< class _t> struct __IsDeque_Unwrap< std::deque<_t> > : std::true_type{};
$ T& c; u( j( Y- L* j/ D4 i template< class _T> struct IsDeque : __IsDeque_Unwrap< std::decay_t<_T> >{};0 k( O' P4 ?/ u$ C
7 i. m7 a+ R+ R" V0 S0 c" ` template< class _T> std::string ToString( _T const&);
* c1 J/ M: e+ b9 S& f# M
- o% X/ h5 w8 J p6 K& ]% z template< class _T, int _Check> struct __ToString_Category;6 [; O7 I, ?) c9 j: t E; W
template< class _T> struct __ToString_Category<_T, 0>{ // Single
) Z# `! H$ ], o( d' t template< class _t> static std::string TOstring( _t const& _v){
' E% I$ ^" }0 ^ std::ostringstream ANS; ANS.precision( std::cout.precision()); ANS.setf(std::cout.flags()); ANS<<_v;' n2 z2 q/ `: ]& g
return ANS.str();9 w. {7 j5 K1 _/ L e2 H
}
; |8 c/ M2 ^8 u7 b+ a7 @ D1 X 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;}( H$ a7 S% |) H1 `
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;}
# { L: [3 W* G0 S8 _ static std::string TOstring( bool const& _b){ return (_b?"1":"0");}! L" `1 O& l5 `( j/ E+ ~
static std::string TOstring( char const& _a){5 q; h6 |1 a$ U6 ^! _& M" I9 j, U
if(_a==0){ return "'\\0'";} // 否则因为她是*结束控制符* 会导致`ostream<<char(0)<<A;`后面的`A`不输出了;
* O w8 a$ ^; F" Y; K7 Z std::string ANS="'?'"; ANS[1]=_a; return ANS;5 h* y5 {5 z0 z
}
1 }& b1 B% ]% F* }% y1 d( R# m% z* ? static std::string TOstring( char const* const& _s){ return std::string(_s);}- _! }& Q; D7 y) l5 f
static std::string TOstring( std::string const& _tt){ std::string ANS="\""; ANS+=_tt; ANS+='\"'; return ANS;}. `! h( ]6 Y7 o* C$ @+ o
}; {" h; |% b) b, k% _4 X5 ^
template< class _T> struct __ToString_Category<_T, 1>{ // Container
4 G; w8 T) p8 Z. P template< class _t> static std::string TOstring( _t const& _v){9 W4 a% a# u6 B/ O' w1 P- ~
std::string ANS="["; bool first=1;9 {' _) v: Q0 t7 `
for( auto const& i : _v){ if( 0==first) ANS+=","; if( first) first=0; ANS+=ToString(i);}" _# d, Q; e5 ]6 l2 j2 |
ANS+="]";
' G" a. D& W5 x9 _; U& L" I& t return ANS;
, U/ f/ \1 |& |+ B1 Z- m4 {' W& g }
9 y" L" v: L5 O `9 N! F };# z+ S$ ]0 y2 E
template< class _T> struct __ToString_Category<_T, 2>{ // Pair4 e5 c1 M0 c' C0 B
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;}" A( k; C: J! Y0 E9 K2 V
};( U5 J3 Q+ U0 i2 }+ S
template< class _T> struct __ToString_Category<_T, 3>{ // Stack3 c5 f( e' ?, [0 P* }7 n9 I
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;}
! G$ K4 I8 `$ r- G };
4 ] W7 ^" C, x9 G' I* L1 F template< class _T> struct __ToString_Category<_T, 4>{ // Queue
1 B2 J7 [4 B" A% d( |; P 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;}
. r$ H1 d G2 W% Q8 f };& O% J1 N2 d3 I' C8 q c9 M
template< class _T> struct __ToString_Category<_T, 5>{ // Deque. v( J9 D% N3 C6 E) ]/ [9 x1 ]# j
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;}% B7 _5 J3 Z0 T5 R4 V. J7 p
};6 Y* K* r5 B; K& `
1 T: i7 g) S7 k- |7 R9 }! A4 A3 s 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)))))>{};
6 }* p+ y$ t9 a2 `8 s/ S2 C& f
& k% f6 G8 r. [0 f template< class _t> std::string ToString( _t const& _v){ return __ToString<_t>::TOstring(_v);}2 F% }, `! }- q! ?
9 ~' F/ }7 X& Q' R) e* N template< class... _H_> std::string ToString_Items( _H_ const&...){ return "";}+ W$ m/ A7 q X* H! p7 ^
template< class _H_> std::string ToString_Items( _H_ const& _h){ return ToString(_h);}5 W& v H. z9 F. g
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;}
1 u6 j9 k! u: f! y7 F0 e}, w, _$ Q2 N$ V
# T; m/ D! j6 O+ e4 i" A1
. V( u! H4 G: x8 z% ~: G: a6 |" h2
3 E1 w* R+ J9 q5 }7 n8 D9 f! m3
* f- O' v9 ~$ D! f1 r3 ?44 ], V/ j# D5 }+ s
5- s- H5 m! R. x. L* U/ K& c, O
66 x: j- E7 j2 R/ w
7' N+ H& F* e; Y- L; j
87 Z* ~. Q a* e2 p& h+ r* ~5 ^
9
8 w8 b8 V" p8 `10* j; [7 b8 z& D4 r) v/ O
11
" h* K& x. E- w% ^12# j5 c' y" x$ e. q! _* z% H* B
13
: m$ w: _8 D+ ^) v7 E/ k5 {14
7 f) N: I# q4 z9 }! T- Y15
9 G4 s/ b/ B7 B, ?163 j$ I$ y) s1 h$ f$ s. P0 C
173 I8 O% ?# @+ f4 T
18
# X* T9 W1 u* w1 y) U4 A, I19
9 I7 |& H5 f: D9 P2 {, I& {20
3 |. B! a* ^' U% e8 F% u21
- e: z. n5 g% a3 {$ d: \# E22/ q) g) X) x# a) p& H
23
' }! Q# O% ?% G# l" s% I24- F5 v0 j1 i }9 x9 N: N
25
( K9 V& o U4 _/ K, c* u26
& F. A$ I) Z% q! ^27
& K0 ?) x; m. T0 ?6 |, L28% z; _, y' }6 R: z) |& Q! y1 v y
29
3 v9 l: Y$ W* J5 @% G30+ [% w! Q) `0 X
31! C B6 g% W( y9 o; u6 t: D
32
W& e% Q' c L6 b5 `33& i3 y, S, [4 m: O
348 U: ^) X+ k5 @
35
) j3 {) N( _9 f; q/ w2 P) f36
& m$ ]9 Q8 h5 M/ D) H37
3 ~' [4 c) D( f0 |9 U4 t38
5 W# x+ ?# K; Q39
- M0 J, _/ u. \7 _40# g, _- }! J1 U l
416 N! j8 [! N5 V0 x( ~% \, }
42
5 _5 e3 j, N: \5 Y1 R4 ~43
1 Y3 v; h- g4 b. w% p! |. N44+ k$ }7 d* e1 \" R+ d
45
# F8 [6 c) M/ J% z n46
0 g- v" I: [% P4 Y" B1 T' W476 M( ~0 R7 j( D) i1 U( g1 I+ i! I
487 [. w( N9 k2 {8 C9 B! K; S( K
490 j2 t) A8 i Y. u; f: L) o+ W
50% z9 W) f2 _4 t0 U: g# D
514 q. j3 y5 U$ E- S% S) D
52
: r1 g( U2 ~* \( c$ L& _53, ^1 M' y$ z* F' b
54
8 |% ^' H# x" j9 `. n/ m8 O55$ O% d+ z' i6 n5 S6 s
56& d* z) k; s( B; j( c* J
57' f! ]4 y- ^! t4 E1 m% d# i: o" F' j
58
& Z1 i8 U3 I8 r# Y' m$ x59
9 E6 }8 J; a' X1 x! @: r& _ }60
H/ u, X7 \ N( |/ l" Y61
3 A4 S& Y: F* S% A% d62
- [* x/ a; [- ]: S639 B( n: ^1 T7 q" e6 G
64
, ?9 H7 Q) p8 V: `2 ]" T2 M: E65# c# _9 a, l% r( g4 k/ A4 n# ^
66
8 Z& H; u% V$ x8 z67: y [9 i4 ]5 b
68$ M6 l9 ~% T" B( y& Y" c7 M/ D
699 M3 e5 n: {: L
70
5 W' [5 s4 m+ [$ A: g3 p* ~715 M6 n$ ^! T/ I+ Q m# C7 a
72# O" B3 {3 t/ g8 `5 |
73
8 H& n) H6 |9 O746 n6 n* Q9 J. Q9 [0 I1 {0 v6 q$ s
75
: O6 M* A9 M. M76. I* ^8 Q+ u1 f4 F0 c
77
4 R! B& D2 z7 G78
6 S @% N8 W, V4 q# D7 N79
& K! m7 n% j4 g) f: }80
) d& t6 S5 V* U, g1 p- N816 Q: g6 [4 J+ X, d+ }
82
( f' Q/ }. u9 ~$ O832 R% C, ]2 I$ D& }2 e" R6 |9 [) a; V4 a
840 c6 F/ l% `0 w% M
85" _5 F2 e7 J8 s" Q
86
- K1 l" s) e9 k8 a$ x; }( ^性质7 d1 p, H* w7 e( h6 w) |
#TOstringITEMS_#% w& T" g+ \* q/ M1 O9 s0 Z
这个宏 是为了: 对类进行输出时 可以直接_cout<< TOstringITEMS_(成员变量...);/ ]/ ~/ Y0 K& y, O5 D2 B
你可能认为, 直接_cout<< ___Debug_::ToStringItems(...)不就行了?2 R* W+ J" ` v
. 错误, 因为在最终文件里 是看不见___Debug_的, 所以写成一个宏 在最终文件里 #define TOstringITEMS_ "";
+ f N3 {& \1 m8 H7 Z' x3 j
1 M, n, ~% \+ W/ t2 u笔记7 f) v, H; v, {3 a! l
#以前的debug.hpp#" e/ Q8 D$ Z) D q6 S
! n( N( \. m: n" o* }6 q% m( S! O
//{ omipusDebug.hpp
- k& E% `* D( \ ? v) G#include <bits/stdc++.h>
z0 k% I/ t) {0 p% A4 O+ j% S; R: D" Y4 N D
#define TOstringITEMS_( ...) ___DEBUG_::ToString_Items( __VA_ARGS__)
9 i, j% h+ k. m3 ^- c#define DE_( ...) std::cerr<< TOstringITEMS_( __VA_ARGS__)<< " "<< "{"<< "Line: "<< std::to_string(__LINE__)<< ", Var: ["<< (#__VA_ARGS__)<< "]"<< "}"<< "\n"
: x8 F, a: v6 [, V: `3 V$ R5 S) P8 \#define ASSERT_( _op, ...) if( !bool(_op)){ std::cerr<<"Assertion: ["<< #_op<< "] {Info: ["<< TOstringITEMS_( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< "); Line: "<< __LINE__<< "}"; std::exit(2267);}. e m1 V0 D g6 G. P' j* Z
#define ASSERTsystem_( _op, ...) if( !bool(_op)){ std::cerr<<"Assertion(System): ["<< #_op<< "] {Info: ["<< TOstringITEMS_( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< "); Line: "<< __LINE__<< "}"; std::exit(2267);}. r) ~8 _! J& u
% |8 U$ I4 O( w! V# D ynamespace ___DEBUG_ {% [! f! i5 D7 m/ Z# s
template< class _t> struct __IsContainer_Unwrap : std::false_type{}; // 所谓`Container`是指 可以通过`for( auto i : S)`来进行遍历的;( i7 G3 r0 G8 r0 j3 `3 R
template< class _t> struct __IsContainer_Unwrap<std::vector<_t> > : std::true_type{};
# E: ^. S9 M1 q0 H0 w* t template< class _t> struct __IsContainer_Unwrap<std::set<_t> > : std::true_type{};% Y* t! ]2 E5 w% f6 W
template< class _t> struct __IsContainer_Unwrap<std::unordered_set<_t> > : std::true_type{};+ [( W! I0 q8 b- i B9 \
template< class _t> struct __IsContainer_Unwrap<std::multiset<_t> > : std::true_type{};
4 v% N. P3 ^( E; j5 S. S7 ^ template< class _t> struct __IsContainer_Unwrap<std::unordered_multiset<_t> > : std::true_type{};
. f! B( d" y1 N# P. _ template< class _t0, class _t1> struct __IsContainer_Unwrap<std::map<_t0,_t1> > : std::true_type{};" B3 ^1 I4 S- R% J4 ?7 M; u6 R
template< class _t0, class _t1> struct __IsContainer_Unwrap<std::unordered_map<_t0,_t1> > : std::true_type{};2 ^# s2 l; c4 G2 s+ C& }: v7 H
template< class _t0, std::size_t _t1> struct __IsContainer_Unwrap< _t0[_t1] > : std::true_type{};/ o i. k8 A- Y; h* y
template< std::size_t _t1> struct __IsContainer_Unwrap< char[_t1] > : std::false_type{}; // 特判, 字符串常量"..."不属于容器;
6 T6 |' m; N# Y5 X template< class _t, std::size_t _siz> struct __IsContainer_Unwrap<std::array<_t,_siz> > : std::true_type{};
+ Q0 Q+ x1 `% E+ o/ J( m$ d template< class _t> struct IsContainer : __IsContainer_Unwrap<std::remove_const_t<std::remove_reference_t<_t> > >{}; // 不能用`decay` 否则`T[N]`就退化为`T*`了;* D* ^; P8 R* D0 p2 J
7 |" w# l2 j' _0 T4 |9 T template< class _t> struct __IsPair_Unwrap : std::false_type{};+ G9 O( |3 w( y7 H
template< class _t0, class _t1> struct __IsPair_Unwrap< std::pair<_t0,_t1> > : std::true_type{};
0 q% _+ D8 A. U* ~6 X template< class _T> struct IsPair : __IsPair_Unwrap< std::decay_t<_T> >{};
$ T7 j7 V& h2 _7 l0 T2 G! g6 _
" O: k" Z# ], q+ n9 u' | template< class _t> struct __IsStack_Unwrap : std::false_type{};
?, D; u8 }' e5 ]4 A, t$ b template< class _t> struct __IsStack_Unwrap< std::stack<_t> > : std::true_type{};
- h9 g; @' [5 g. Y template< class _T> struct IsStack : __IsStack_Unwrap< std::decay_t<_T> >{};
5 A6 k, H! X6 S2 y0 C+ {
; ^: @1 ^4 d4 o# ^ Z template< class _t> struct __IsQueue_Unwrap : std::false_type{};9 c# `" l* d. M) L& l; ?
template< class _t> struct __IsQueue_Unwrap< std::queue<_t> > : std::true_type{};4 \7 t1 R4 B' {$ k3 |9 O4 U
template< class _T> struct IsQueue : __IsQueue_Unwrap< std::decay_t<_T> >{};8 b. J, P' h0 e3 b# a
8 n/ X6 N# L9 B. _- ~( }
template< class _t> struct __IsDeque_Unwrap : std::false_type{};# s* G" n! |. n+ I5 z
template< class _t> struct __IsDeque_Unwrap< std::deque<_t> > : std::true_type{}; c- b! M; T, D9 E' B/ o6 |9 Z
template< class _T> struct IsDeque : __IsDeque_Unwrap< std::decay_t<_T> >{};
: |' }0 `" _- E3 i* c. }. m. y' `5 d4 L' j: g
template< class _T> std::string ToString( _T const&);1 [; S4 J3 r$ R$ c8 t$ ~" X
- W6 M4 E( R0 \6 f1 u) r/ s template< class _T, int _Check> struct __ToString_Category;2 y- L4 ~. j$ i4 D5 {& j. L
template< class _T> struct __ToString_Category<_T, 0>{ // Single
3 h* J' {, O) b! B! o _ template< class _t> static std::string TOstring( _t const& _v){
: H- ]' a. L5 B* u std::ostringstream ANS; ANS.precision( std::cout.precision()); ANS.setf(std::cout.flags()); ANS<<_v;' O; e$ t7 b7 B& J3 n. y0 r
return ANS.str(); _7 x) b8 P3 t
}; U- Y: ]- F& K2 s/ c1 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;}9 C$ }9 o: ?/ U* z. l% I3 C b: O8 k
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;}
8 d! j/ e& L& b7 N& |' I/ ` static std::string TOstring( bool const& _b){ return (_b?"1":"0");}# ?1 f5 z5 }( B" H) H3 H4 z6 J1 n
static std::string TOstring( char const& _a){
7 X* z3 A6 ?5 f8 n, S std::string ANS="'?'"; x# N$ D( r. |" k3 P9 l
ANS.replace( 1, 1, std::to_string(_a));6 e4 l# C1 a, n P, @
return ANS;, B' ^4 h$ M+ u) Z) W. i
}1 _9 t" E9 T1 @$ g3 F& Z
static std::string TOstring( char const* const& _s){ return TOstring(std::string(_s));}
- F- p% K' k0 o/ w7 t: T static std::string TOstring( std::string const& _s){ std::string ANS="\""; ANS+=_s; ANS+='\"'; return ANS;}
+ i+ s8 I9 e7 l9 q };" ]& H4 {7 S! I" q0 q6 s" k" }
template< class _T> struct __ToString_Category<_T, 1>{ // Container8 q, ^; ], I8 F3 n; I/ j4 G3 v
template< class _t> static std::string TOstring( _t const& _v){
6 H! @, X9 I1 s4 j% {) b std::string ANS="["; bool first=1; for( auto const& i : _v){ if( 0==first) ANS+=","; if( first) first=0; ANS+=ToString(i);} ANS+="]";. O) U0 g( W: p
return ANS;
9 A& D) a4 S8 Q4 n7 |: b }
9 M# s' [1 W* i% x };" @0 d+ |) E" k# d I& N
template< class _T> struct __ToString_Category<_T, 2>{ // Pair
% |6 C6 I5 S' l ?+ V5 E) \3 H4 `% `7 h 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;}2 |& T: r& v0 }# I1 e+ f, f, }) s
};
N! I0 o3 ? o/ ^9 e9 \ template< class _T> struct __ToString_Category<_T, 3>{ // Stack
r0 E5 c! \/ y 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;}! D1 L E& ?! X2 O5 Q- Y
};
# p# v6 K2 G' g template< class _T> struct __ToString_Category<_T, 4>{ // Queue
) l" H$ a/ g6 `& B8 C6 e 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;}1 U+ j8 D5 l% W2 P. I" h: _7 F
};, b# X6 b' n5 T. H- Q
template< class _T> struct __ToString_Category<_T, 5>{ // Deque# h9 B9 q1 Z0 b; b
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;}
; e! G# p! N% m& h9 u4 F };# J2 Y; ]. S8 Z$ A1 G5 o8 W7 ~, [
& Q6 o5 s2 l5 Z& n, |, n
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)))))>{};
& p: z. w" G5 O+ d; L0 N/ }% a) L" I; U# T& n" ?; O
template< class _t> std::string ToString( _t const& _v){ return __ToString<_t>::TOstring(_v);}# |* Q% i9 }0 s) D( F2 ]
, b& V; r( a) a9 m. b) O template< class... _H_> std::string ToString_Items( _H_ const&...){ return "";}
: c) I4 c S. i, h+ _/ b) y1 r template< class _H_> std::string ToString_Items( _H_ const& _h){ return ToString(_h);}- F4 C) Z0 e2 q7 q! N
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;}
& i* ?% \' O4 L# { x; M}
3 |8 B% S6 ?8 d//} omipusDebug.hpp1 G c/ Q. o! L
1" e% D$ t. Y" v- k) W3 K
21 n/ z0 ]( j7 r# T
3
! g! m5 {$ P# B* m& w' m l% P4" A$ D. q& S! p) I
57 d, N2 E' D* d" q3 B' r" v
69 u9 L% H6 W {( O
7+ z* r: l# r' c1 @
8 I+ f* Q X% S/ Z- t- H; y* `/ u* V
9
9 v; V6 R7 u, H# c9 a& C. }9 T10) J+ B: ]- z8 m- J
11/ N8 y1 g: w* ~
12
- v0 C1 U. v2 a# g ]0 E3 L5 k! n o13% ?* U8 }: ~$ ?" Z4 D2 b) Z
14
. t' n& ^7 O1 _154 b( t0 N; P# E# ~/ N
16: W! z& i! @$ v, K2 r) p
17' g5 M& I' K# x+ |
18
" d J/ \$ y3 z7 k P19
4 {( D2 `3 W; ^9 K" a/ H; Q X' ]20, Q4 {" U; i' V) V8 T9 I9 C+ |% h8 o
21
; y) a) Z N% q# ]7 S7 U, v227 z6 z3 X) o& P* t5 S% w% i0 @
230 D! B) F# y- {: }
24
; g' J0 {- R# ~, z; ?7 h$ i2 n, c25
5 E, j/ j& F6 X4 \% d" O268 W9 z- ]. L# b( V: t6 [$ u8 `
275 p0 K# Q) q I! |" v3 ^
28
5 G" U9 g( \9 B: q1 \/ ~29
+ W* }4 ?; B% P9 F, ]30
- Y$ U! b2 F0 `5 w$ l! c& i9 \318 g @3 B6 [" H; A* a* [
32
3 W: I) k! D9 ~0 ?! Z2 d( b33
/ X' G$ s: _' x5 I q( D3 T( {34
* M Z$ l1 x& z, j4 J$ v35
* u6 G" Y& w# ]5 }- D) a36! j3 j" E: K3 ]8 l1 _' N# w! k
375 ^* {' g6 \& f* T) ]) C" W
386 P, {; h5 X! s7 J
39
: B( @+ U7 N% k. d3 M6 T40
+ h5 x* x2 K! W41
0 \' s+ g/ ]' L" L4 I8 p+ B2 O Z, y42
* L$ O% W6 J; r1 M7 R- H43& O' z( O! P) K4 |& X+ R p
44
$ Q, e% [/ N2 V4 B9 t3 G& S* ?459 A3 V- L1 U. K# M. x& e
46
% b, q l6 s/ T: v: e47
5 S: I5 {- M S6 X( ?+ c! e487 U2 R- X5 ]" x9 v
49; V6 m" h- ?* p n
50" n7 O k. `& `
51& L4 ~9 j; T2 K0 [: S
52. p, G: b3 l# z
53
# k* o+ @5 V h6 { S' x549 d" n8 z- a; B8 q: v; G3 s8 A
556 T* L+ H, E, ~
56( E$ ^+ J. f2 l$ l& n5 t' K
57
2 E4 \7 J& m1 D( C( d0 p% |58$ c7 A; B8 F% T. k3 Q: o: z
59
; S# q: g0 Z9 u600 B. @" M7 T/ w1 f7 U" B$ M' M+ n
61( h, P$ M" H" X
62. U2 `9 e. T9 @! s$ I, p
631 a2 h( J+ S5 s- X& m8 x
64
& W- q+ f" M1 P$ B65
# ~: |& }1 y# ^* j+ j66& Y p. B1 o: M. F7 u
67
8 j& N- ?- U0 Q68
% p" G9 }& D8 \ v691 B0 B' F K3 F+ n ~( P" n
704 y& E1 G+ i, \: {+ C/ U
71
}; m& }' d: |+ }72
$ L* w; ~9 H% H73
+ A9 Q% J8 r$ O" U" F% K74/ ?' \9 C V- f) f
75
3 w/ g9 _: r. W7 {0 \; j v; S764 l+ y' A; L& Z' ]* Y( k
77
7 U8 J5 p* l/ V2 x784 I0 X7 v: q* e4 B2 `
79
. V4 H+ I( r" p; V( W( ]80% E R& `* Y) B. b
81
+ k( N {. X, a( B82
/ |( D7 B6 e6 E7 c5 q$ B& x: F83
& `- K( l$ L( ~$ Y& ^8 u( E8 l4 C84) x5 F4 r1 g: d% }( M% X
850 e6 l; k8 s& M
算法競賽配置+ R- p: J, ~. ^: \5 b4 M' Z
QT_Creator
+ Z, ?9 o( ]8 I7 m/ v4 r創建一個控制臺應用, 然後在Pro文件裏 添加CONFIG += c++17 (原來是c++11 修改成17);$ G# J z4 U( E6 e
- t$ |6 ~' E' a% }對拍文件
- y0 O5 ?/ c7 m; X: G`compare.cpp`
' s+ H" b( g7 L0 R
# V z/ t1 l4 t rint main(){: N7 R! r1 s9 x4 ?2 y* _! }% t
vector< const char *> Init{"build.bat generate_data",
0 x2 E# ?7 |/ i/ U. d" Z) [ "build.bat supimo",
" {. L7 S4 K! |7 [& a( x# P5 Y "build.bat correct"};' B1 P+ U& l2 _
for( auto order : Init){
' @, K" s7 R5 F: x% t auto errorCode = system( order);% R9 N: x0 o, }* M ^& v( R
if( errorCode != 0){ EXIT_( order, errorCode);}
0 j$ K% l# w" R% r' ?6 u }
* X* }. D- K' a/ T" g3 R' K# c# A0 g0 z- e
while( true){ {5 t, M6 h8 D% L6 Z
static const char * Ords[] = {"generate_data.exe > data.in"," V3 Q* h0 r. k
"supimo.exe < data.in > supimoOutput.txt"," p2 ^* y. W) G: p1 \! a
"correct.exe < data.in > correctOutput.txt",
# t) d+ H* `* n1 s5 E# ] \ "fc supimoOutput.txt correctOutput.txt"};
; n7 s& Z* `6 _( r for( auto order : Ords){% e% i; ^( z5 M: v' a! u4 W
auto errorCode = system( order);
# q, t5 Q% R6 `& z3 t if( errorCode != 0){ EXIT_( order, errorCode);}
" G) v$ C( J% Z: [% D }
1 f& ^& y4 [( Q# T cout<< "SUCC"<< endl;. }! N/ Q+ C; @- l& e
}
; ]9 p% l" v1 p3 y
. ]3 q5 L4 e+ j9 u/ K* s2 O8 U return 0;
8 }5 m# o0 m1 t' X- e$ j) C}( [% o. h3 i4 g. `- T( B- y! A# E
1$ n2 |% o+ O5 N! I2 C/ F
23 i7 d( q- m* j5 u# \% h
3- U0 ^2 z% h& h, M- Z$ L1 c
47 F0 u$ L6 n a6 E# j n
5) W; Y5 H- n. u& ^3 u1 a- t, i
6
) C0 D% u1 ?; O& ?4 z" {4 y7
5 d2 b! @) U' t8 l& I: e2 R87 i$ e$ N/ b% y2 @, ~% ]
9
; @$ y( B. }: t6 |8 ^10
1 l6 r* Y3 A( \: n115 `4 ]% w! N3 S$ ^
12
1 W y" ^. j7 x( u) w2 d; B$ M* c13
; w# z2 L1 Y2 l& T14
8 U$ u; _2 w" l, A15
7 a( n( x3 {# u9 ?160 g# p0 E/ m7 e! M
17
; r4 @' u$ [/ O3 h2 @( v18
. u% a/ Y: }3 X& C9 ~8 K8 T k# Y19
2 Z# o9 }3 y. t3 b X) ~20
, ?9 [; r4 n j: V% q21
* W, x& @. J9 O- L! C, g22
- b( D1 S. ? \; |+ {23) d( b2 \3 R" R5 S' Y H# K: p9 ^5 q
24
" A7 h& d& e& e4 g. J( h- {25# x3 q) h6 l7 V/ \$ b2 Q7 S5 X
Bat代碼
) s& K% s# P6 i2 J7 }4 l Ubuild.bat$ |) l6 W7 @; P! J* G
@echo off# t; A" w* y* y; Q4 Q
del %1.exe8 x$ ~# c# y) T% [* ]8 p7 @
g++.exe %1.cpp -o %1.exe -std=c++17 -O2 -Wall -Wl,--stack=268435456 -D"__ISsupimoENVIR_"
2 J$ } ]/ \3 y0 ~: _
# q- k% a: \7 P; P! q7 J5 D6 u' y@DELI;
6 O' D: e' s! ~& S4 H6 M
- y2 R. M5 L5 h1 u! drun.bat
5 I7 H/ v' d1 C Q# H5 z/ Q@echo off
% ]1 \. [" [7 F$ N2 C+ ]0 p%1.exe < input.txt( O! M4 s8 p7 j/ l
2 V( }9 u: D# W/ W@DELI;3 d6 l5 @" n3 R J5 b& X, m
/ Z+ J; y8 I4 r4 w% O5 q
build_and_run.bat0 |7 Y$ s7 i* u6 J9 w: ?1 i
@echo off
& E+ e& ?6 t. d5 X# Pcall build.bat %1
! ~# O e! f. C% R, mcall run.bat %1 %2
4 u: o% C8 Q( H% G D% r; |1
5 y7 K3 F* Z" F2/ \- \: U+ s- o- b
34 X; ^/ k" N- Q0 o
48 l; c- }& q$ b: {" R4 h6 w# H
5# w( }( O- n1 W& X$ S x! @
6
( d* w$ q" n) ?+ D' E7 r3 _7+ O) w8 n4 e$ I& _6 J
8
" p. h, J0 I' K9
3 _/ P8 H, `' e" d& \/ h) }$ e) K5 A107 _6 a: }$ k9 Q9 F1 s
11$ Q# C5 _; A4 I
123 w/ @8 P; B7 ^/ [) q" e2 H1 \$ S" D
13! I; a9 V& h; @4 O% W' \8 U/ p; [
14
2 Y3 Y8 s! G ~! X# t9 W15
$ J* E* W) b, Q. P, n6 p16: X: T& W3 ^, G a3 F
17
+ ?$ w6 t9 [! f j( B) F源文件. h, |2 n2 s Q* k4 B/ Q
#include <bits/stdc++.h>+ l/ v8 t+ Y4 \0 A/ s3 I# D+ {
using namespace ::std;
* V# N. ^/ c) p4 g
. r- d! V! G4 B: z' _ e//{ ___SUPIMO2 K% z: ~, w/ X s7 W4 x! v
namespace ___SUPIMO{( N9 |. u h6 r7 ?
//{ Macro
9 v" {: c* C7 t# y8 b% i h/ q#define ASSERT_CUSTOM_( _op, ...) if( !bool(_op)){ std::cout<<"Assertion_Failed(Custom):["<< #_op<< "], Hint:["<< ___SUPIMO::Debug_::__ToString_items( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< ")\n"; EXIT_;}
8 J) v4 y$ Z, D# ^5 I! P#define ASSERT_SYSTEM_( _op, ...) if( !bool(_op)){ std::cout<<"Assertion_Failed(System):["<< #_op<< "], Hint:["<< ___SUPIMO::Debug_::__ToString_items( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< ")\n"; EXIT_;}
C* O/ f. I1 z6 I; `: q#define ASSERT_MSG_( _msg)
' A5 q3 R3 w, d6 R( e% M3 _#define TODO_RunTime_( _msg) ASSERT_SYSTEM_( 0, "@TODO: " _msg)
5 q$ {7 b' {3 c _#define EXIT_ std::cout<< "EXIT: Line("<< __LINE__<< ")"; std::exit(1);0 {% x& p. D8 c1 V6 w1 d. o
#define EXIT_COUNTER_( _max) { static int cont = 0; ++ cont; if( cont == _max){ string str = "EXIT_COUNTER(" + to_string(_max) + ")"; DE_(_str); EXIT_;}}
- v- d3 h! Y# X% U#define FOR_( _i, _l, _r) for( int _i=int(_l); _i<=int(_r); ++_i)5 S' n* c( D+ M
#define FOR_R_( _i, _l, _r) for( int _i=int(_l); _i>=int(_r); --_i)
. f! E: z. F, P$ G Z9 u% C#define DE_( ...) if( ___SUPIMO::Debug_::___IsInDebug){ std::cout<< ___SUPIMO::Debug_::__ToString_items( __VA_ARGS__)<< " {Line: "<< __LINE__<< ", Msg: ["<< #__VA_ARGS__<< "]}\n";}2 J8 U( t* L4 g7 M1 G1 v$ }$ V
#define NOTE_( _str)
) K; O. X7 N0 F, a8 G9 ^) Q8 s//} Macro
# ?$ m1 y* s! D5 l5 f2 i; S( g# Z( c; X; y
namespace Debug_{0 R; Z" d A" ~" d; O
static constexpr bool ___IsInDebug = 1;
' E! {" ]" k$ Z3 e! c, W/ D } 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> &);% K! {9 d/ k$ a T5 K# E9 v
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;}( \7 O+ B7 N) S0 Y0 q
} // namespace Debug
1 r3 T' d8 I- C S5 G& P2 P: J. L+ e D3 i0 Q% r8 Q# @
//{ Type
5 ?/ [$ _7 T% S. f8 z& D1 otemplate< class _T_> using Heap_small_ = std::priority_queue< _T_, std::vector<_T_>, std::greater<_T_> >;3 W/ d! T4 P; `! o2 P* O4 Y
2 R4 u) p% H' }. x& H5 r
struct Double{- D6 F- Z- Y& q* W$ t& D* d
using __Type = long double; __Type Value; static constexpr __Type __epsilon = 1e-12;
0 _( X. i, r, K$ c. b1 G 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;}& L0 d; Q B: L4 U- N9 F
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);}
6 a, J' p2 u& B& w. o/ M- N' G1 E 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;}
' H0 f) |; O" p5 Z- \! l& t}; // class Double* L# c" M+ V& x1 i& L+ b
3 i3 Z9 q& M& A! G) E5 I1 O
template< class _ModType_, __int128 _Mod> struct Modular{
1 l8 P, h, I1 Y( O6 w5 t& K ASSERT_MSG_( "_ModType_必须是{int/int64_t/__int128}");, R' e3 W" W, D) F0 ^1 P+ P' n, H
using __UnsignedModType_ = std::conditional_t< std::is_same_v<_ModType_,__int128>, unsigned __int128, std::make_unsigned_t<_ModType_> >;
/ W4 \7 r4 i" u* x) W2 {4 J2 K inline static conditional_t< _ModType_(_Mod)<=0, __UnsignedModType_, std::add_const_t< __UnsignedModType_> > __Modular = _Mod; __UnsignedModType_ Value;2 @7 r, s$ v! O/ W! f
Modular():Value(0){} template<class _T> Modular( _T _v){ _v %= (_T)__Modular; if( _v<0){ _v+=__Modular;} Value = _v;}
0 U. p2 ~$ Q# q0 I7 v& R inline static void Set_mod( _ModType_ _mod){ static_assert( ! std::is_const_v<decltype(__Modular)>); ASSERT_SYSTEM_(_mod > 0); __Modular = _mod;}
/ L/ b9 F7 Z- M1 ?8 E 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;}/ J" v# Z; w4 ?/ l5 m, w
}; // class Modular2 h) B& e0 H) H$ G' t+ W
//} Type/ {* {" D8 Z/ ]0 ~* Q
: T* Z1 z, U6 J9 y. W* pnamespace Integer_{
1 [ _9 H6 i- h0 Q: X& N; S 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;}( C. _: o& Q, F8 w3 f
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;}, \* n0 b) ~; a. v0 M
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;}
" u2 R3 y. M/ |- u8 l template< class _TypeRadix_, class _TypeNum_> struct Radix{ // `TypeRadix: 每个进制的类型; TypeNum: 所能表示的最大十进制数的类型`;- w( F0 L/ M% c3 {( x9 A. X/ x! F: h
std::vector<_TypeRadix_> __Radix; // 比如`Radix=[2,4,3]`, 那么所有的数为`([0-2), [0-4), [0-3))` 即表示的十进制数范围为`[0, 2*4*3)`; (Radix累乘值的大小 就决定了`TypeNum`);
9 }5 r2 D( g) E0 y( U: Q std::vector<_TypeNum_> __SuffixProduct; // `SuffixProduct[i] = Radix[i]*Radix[i+1]*...`;
# F/ q) |- M( I* v$ {5 ~ 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]);}}: v5 L; ^( D9 `- Z6 q# n" e
_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;}
3 K" V" O8 H3 q1 z" ~8 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 ~/ {9 S8 y g B- [, A
int GetBit( _TypeNum_ _num, int _ind){ NOTE_("`ind==0`是最高位"); ASSERT_SYSTEM_( _ind>=0 && _ind<int(__Radix.size())); return _num / __SuffixProduct[_ind+1] % __Radix[_ind];}1 K' [0 o2 G7 Y, R( K* w: E
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];}
$ T; L9 T A9 ? };
4 |6 e7 l6 z; I4 J namespace Binary_{% J( J/ c1 U& _$ \( {+ q
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;}
, @( h5 [" ?, M7 M 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;}1 U7 K& `' S+ c0 V$ C
template< class _T> void SetBit( _T & _num, int _ind, bool _v){ if( _v){ _num |= ((_T)1 << _ind);} else{ _num &= (~( (_T)1 << _ind));}}# F2 K3 I! A7 c
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);}% u& r) S" b* L( p `* q( w+ o, V
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);}
' f9 w% R; @& `" D$ Z 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);}
$ S) Q6 G5 O8 S 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);}& A+ H9 W" j! G* F* a
// #枚举二进制子集#: `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]` 一定*严格递减*);7 E; a3 V' c) @# R& Q2 r9 ~' a
} // namespace Binary9 e/ R; @" `: J3 g) W+ r/ W
} // namespace Integer$ f/ D$ _5 q; J0 Y S
) \& S0 W/ N9 i, f' b9 p( u" c
namespace String_{
+ Z6 e7 \! o w/ W+ U4 Y$ t 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);}- n7 P3 I. v+ V
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;}}. q) w/ B7 N+ ?3 W6 A$ \0 }5 h
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;}
4 @4 n0 f3 v! V3 B$ I* u} // namespace String
' _* U! D! J( F* y9 b! A- Q; S' H2 L& V
namespace Random_{
4 D& I: l" l. ?6 z/ F/ Q0 F0 M 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());9 L9 Y( q2 P( `9 X+ ~$ P
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);}
4 b" F7 o/ H8 g, n4 t} // namespace Random
( u0 V5 [* W: c; g0 M, h
3 o( z. j2 N& k1 w8 R9 G3 vnamespace Object_{; H) c/ t- Z& ?' G5 O8 E" E
const Double Pi = std::acos((long double)-1);
& o2 a6 ~, j* W. I! Y. _- u 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;};
$ I+ ^9 V+ V& m3 c template< class _T_> constexpr std::decay_t<_T_> Int_0x80 = __Int_0x80<std::decay_t<_T_> >::Data;: a% e1 U( b$ r1 y7 w
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;};
* A% ^- y( T Y& z/ p! I: Y template< class _T_> constexpr std::decay_t<_T_> Int_0x7F = __Int_0x7F<std::decay_t<_T_> >::Data;
& W& q' Z8 j' O/ o. x} // namespace Object1 f5 i; ~0 e9 x. O3 A
# ]$ v# F( D" Y) `& tnamespace Function_{$ _3 T K7 j$ [5 _! D4 ?
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;}
" S7 |- f+ R/ }+ K8 n+ k 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);}
8 Q2 }0 Y( ^1 q0 ?1 T! D template< class _T> bool IsInInterval( _T _c, _T _l, _T _r){ return (_c>=_l && _c<=_r);}, r5 r5 {0 s7 Q/ C
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;}, h$ O1 z6 z9 c( N
} // namespace Function; X7 a! g- C$ T8 M
$ `% `. ]4 Y* z' c; ~8 s7 O} // namespace ___SUPIMO
; I' i' Z+ b9 Z4 [5 e3 \# r6 G* @7 x0 w! y% M5 w1 A2 W( _, P
namespace std {) u' x! s4 X: S& P
template<> struct numeric_limits<___SUPIMO::Double> : public numeric_limits<___SUPIMO::Double::__Type>{};
. r0 k! m6 S$ y# O' E' e$ R$ M template<> struct __is_floating_point_helper<___SUPIMO::Double> : public true_type{};
) r- g: S" p* t4 _ template<> struct make_unsigned<__int128>{ using type = unsigned __int128;};
- Z, n1 | z# G6 i% s# G P ___SUPIMO::Double abs( ___SUPIMO::Double const& _d){ return (_d>=0 ? _d:-_d);}6 w- }- E# a5 X% C
}3 i; q, e+ ]& X9 K) ]6 A+ s& E& T
//} ___SUPIMO
3 y8 _: F6 }2 l7 i, `, T
- V3 _' O+ [- _/ V# b# vusing namespace ::___SUPIMO;
8 p+ T5 v$ N2 {& }1 q5 d
) L6 U/ z, N1 i2 z" n# Zvoid ___Solve_oneTest(){3 Y( o; w. k7 a! y
7 ^1 A; O) V$ i/ c8 ]+ T$ P}
! ] b: C. L4 Q' s" Yint main(){
. i$ H" Z7 x! w [) W. y std::ios::sync_with_stdio(0); std::cin.tie(0); std::cout.setf( std::ios::fixed); std::cout.precision( 9);3 E6 L& q( c' d) _. z) _* G
8 g3 i: W6 s+ o2 z' J" K0 b4 x% q
auto ___Work = [](){ // 必须严格与*题目*的录入格式对应;
' t% ~7 t/ r4 g" x# S constexpr int8_t mode = 0;
) u5 v3 R% w& p, o1 @ int testsCount;* a& m1 G+ Q L
if( mode == 0){ testsCount = 1;} else if( mode == 1){ cin>> testsCount;} else if( mode == 2){ testsCount = 1e9;}
5 E( P/ b w0 ?: N ~ w for( int id = 0; id < testsCount; ++id){7 k6 s! d! s: }7 s, [, A
if( id == 0){ // Global_Initialize
; q: |, ]- e* ~6 }4 |6 \' v# g" D: @# O" O. Z3 h& p2 Y
} }7 H% Y7 e9 a1 G' m/ Z3 F
___Solve_oneTest();
9 ~6 {. c: M# G- T6 z) B5 z }
9 F; ~# |2 f& m };# b6 W7 \- W9 `$ g7 q
if( ___SUPIMO::Debug_::___IsInDebug){
' y: E e+ e" w e) B+ v0 L7 B for( int id = 0; id < 100000008; ++id){( {8 g) h p: q6 n! Y0 S, I* E5 ^
string flag; cin>> flag; if( flag == "___INPUT_-1"){ break;} ASSERT_SYSTEM_( flag == (string("___INPUT_")+char('0'+id)), flag); k3 Q1 d$ d3 I. E- i
___SUPIMO::Function_::ClockSplit();1 v: u/ Y4 a! s1 Y1 Q9 k
std::cout<< flag<< ":\n";
/ Q. \( P! X; W2 a O/ ~% \3 | ___Work();& C* W2 ?+ u6 C% R8 w
std::cout<< "\nTimeElapsed: "<< ___SUPIMO::Function_::ClockSplit()<< "\n\n";5 C: [* P( B A" N# ~/ l5 ~
}6 A3 T2 I" ~- {1 V0 K: g" e
}8 R% \5 a. Q0 d1 Q
else{ ___Work();}
, L; C+ b2 Y2 c$ ^+ }- V+ x8 }
* \/ W% L x* y) U7 X return 0;% H* _1 k: r8 V0 ~0 u# w8 H& w
} // main
/ r3 @8 ^1 V) d0 r( J5 X, l" [4 N, b( {8 ?4 B( X- S+ f
namespace ___SUPIMO {1 O |5 Q4 [6 c- r* @' z6 l! L m+ w
namespace Debug_ {+ Q- |7 O- U, H5 g* p ~; j
template< class _T> string __ToString( _T const& _v){ ostringstream ANS; ANS.precision(cout.precision()); ANS.setf(cout.flags()); ANS<<_v; return ANS.str();}* T9 Q7 V' X2 Q7 k% 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+")";}
( a U1 s' U# 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+")";}9 D1 j5 F9 U8 d
string __ToString( bool _b){ return (_b?"true":"false");}
M6 L+ q4 F, } string __ToString( char _t){ string ANS="'?'"; ANS[1]=_t; return ANS;}
9 [/ B, s. X1 W% g m& ~ string __ToString( char const* _s){ return string(_s);}, v( R% T1 W/ L! R, W* r. V) z9 M
string __ToString( string const& _t){ string ANS="\""; ANS+=_t; ANS+='\"'; return ANS;}1 o. G' f1 t' C% x( 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;}( l! G# ?5 I. @# @
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;}
6 ~9 c8 r3 J4 t! v3 f1 L; k 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;}% ]2 T) k8 w5 o0 c5 T
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;}9 n. S& s5 g% p* Y! x/ e# @5 G* z6 s$ ?
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;}
& i* n' S0 ~! m 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;}
3 T' g# n; p1 y* {) E6 V 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;}. K8 ], D2 T7 @: i9 e' }* ^
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;}
4 S n- L$ |9 [3 O 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;}# X7 s4 k% X+ u( I* g) [- u( _
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;}
* [; B2 P0 m9 U+ d 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 H: h2 n% q' _; x& ? 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;}+ [9 Y- H" H" P
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;}
# W# S* E) U! a4 |" W( `2 i* o }1 J/ X3 j: J0 Q: ~) c
}
, \ W3 ?# c" w% P( ]. v" h4 P1
' P$ N/ k5 R% ?3 a9 {24 u7 @6 T; {3 N9 j9 T5 y
3
7 j" i) u# t# r* \49 `; a `: e% f+ E& k( V- Z
59 k" H7 I5 N: }
6( l- y( E- y; ?) F! d& }
73 \. z7 o7 U7 |! H
8. {$ @5 B# d; M9 c
9
5 Z* n3 A2 j% ^' u! h3 n6 K107 L# Y2 z' [6 M5 O4 m; H- l' }
11: l( D; y; E/ E- F
129 s' W( G2 C; P: P
13
3 ?3 c; k/ s5 @. A6 d5 Y0 s2 d14
4 D+ v) C; w i15
' H$ z1 V0 t3 B6 p) z161 }( f# x! U6 }5 u4 F, G
179 H7 j+ ?9 f7 E$ E
18 h, f0 F* O% N/ d
19
: m2 }( O1 y( `$ n8 r8 \8 E, r206 P7 K' e. T- U
21
- i8 B2 o5 T1 j: t e: z- f: R22! K8 E' l4 S: k0 T
23
9 _! }8 W) v0 Z4 W' }1 F. I243 e6 }0 _$ k- t' ^: P
25" _& d; T% o2 y
26
" S g- Z: P/ x! B1 D# L o0 H27
1 H7 { \5 ?% E! g& H/ n28
2 A# n: d' K8 J0 H29# Z/ [1 G+ ]( j) c- I% D
300 f! q% P! k |; @
31
. y6 O/ a$ j9 g3 V8 x32, Y8 q+ p1 H% f# z
33. Q! R3 ]1 m# Y1 B6 A1 O- Z3 _+ t
347 }- b6 f0 D( [+ n/ N
35
" N6 _! o) W5 J3 o- T36
7 r& ^# x0 v4 L) g; |37 I$ z3 k7 u H- j5 g$ Z
38
! _4 L% [0 }0 ^* n1 w( L39
* s6 Q+ |0 Q. X. g; O) A40
+ L: P. Y0 k# X9 J/ W9 ^8 p8 f41
/ n% w# y9 `+ q: a9 Y$ J0 u# K# l3 x42
& L5 ^2 i- z% `* G43
: A) _4 z; C; L9 K e8 N2 }441 } v! f. ?% b1 h& J
45
: a1 `& i& ]8 D* E; H1 ~+ l469 Y+ L0 d4 p, ^% d% _
47
4 c1 {+ r. P; \" m6 `8 v" g48
2 I8 _- r3 t- ~! _ W49
' h+ p5 W- |+ ^! D3 i& Z50
6 Q3 a6 J+ g# ^: U% d8 F1 W511 h, O2 n& L8 G
52
% m3 P0 S( @' ~53
0 S8 e- | ^' J9 `0 \/ }54: s/ z. \ v! }; c! J
552 e3 D, u2 b8 J3 U
56
: N4 I3 u7 x7 r) D$ \57
1 M5 x; _) |8 Q( n58. s6 J9 J& o4 ~ f) P
59& J+ I6 }. K2 d8 k s
60$ \, ~7 d" W3 y3 B
61. v! F6 i( A% Z
62
- ]1 y* V/ x, t, V9 O63
# N; e, Q: S% m" D! V64$ D5 j3 @' M& g, z! A4 S! J4 W
65
$ b+ r" E: i( o# @1 E7 @" U66
8 u! C2 {" I4 ?$ q67
9 W3 z) J( T8 Z6 {3 c68" c X* X/ c7 V8 L9 O) @4 g
69# K( w: f; T. h9 x" r4 U$ G7 x' [
70
/ b6 _8 m8 k4 N, v. n9 ^4 }( ?% o- A712 x9 m& }& T0 |! M, A
72" a2 J6 i. A _! X2 r) l/ u4 n6 _
73
3 j( N) F" g5 O& C2 B746 h0 c- {9 h" S) s* ^: ^- m; F
75
( P- M& q; {7 ~76
; R# ?; }# s8 B8 Y( Q778 V( J) q8 ?! f8 z5 E$ \
78
9 h& o3 `! v* ~* o$ l. W79
% _1 S& a0 o1 d" b3 a, `2 K80
q4 L5 g7 F( c! X. v6 `81
$ g8 N8 j% b: L0 j! f) |82/ f2 G+ h- |; w* D) V
83
. e& K! \% ~% E5 ^840 c* c+ P" u5 W* [" f: j% D/ U
85
- n* `. C( ~$ L1 ^, t: @% J2 l86
+ V. A% J4 H$ S8 v m+ s87+ ]' O/ E6 T' ?6 @" e
88' t& E- t: {& t! f
891 g$ S' Z5 U. {
90
- z$ T; v+ D5 S e( Z( y912 @% u( `8 [+ \* J+ V
92
0 `0 I8 v% g, a* ^' x7 ~93
5 \0 R/ b; N: C3 g2 ~: r9 d5 F94
: a/ n3 v$ R. I) L' X }/ n! _/ f95
/ D( w$ q# V* I& D96
y5 @/ F# j# T, Z4 _6 e M7 n" E( R1 }97) L$ u7 G( K' N( v- @( V9 ?
98
9 L6 o( ^% b+ Q% K `4 C" W# f6 e99
; O' M0 X) S. ^6 K) j9 U100
" {6 I" K6 K7 |# t9 F( A s101. `2 \" T8 D c# J7 F; `
102
. H% D( m/ V! o$ {103
: v9 V8 B& ~& E2 @9 T7 }/ w/ f1 i: k104* e5 m" Q4 A) V9 N
105+ t$ ?8 w9 B5 U( E5 j
106/ V6 I& i7 L6 Y$ s! A
107
. N1 V8 q; X% N: Q2 z0 ?7 F1088 L) r& V+ ?! F' z; d8 I
109+ q: O: u6 v( C! b- g3 ?6 n
110
) b3 Z8 z$ G/ r; F6 L0 _111
1 x( ]; f( ^; A/ A+ g112
, [! V, d' I& p; B) a4 ]113
1 O) o! q/ T# {- o; Z114
" n# l' w C0 ?- {5 }115/ t4 d( T$ {) t* Z/ E
116
' {. P! Q q, h5 H8 y$ b9 k117
) P, o9 |5 ~4 Q0 s1187 u2 [1 B. U4 _' L: R U& l, B. I
119
6 z% m1 M s0 M( E1203 E2 A% K3 s6 U: t1 ]4 Z& J
121
- p% n( V3 n8 [6 ^1226 w1 N) w5 G" w+ r
123
0 J1 w3 ?! L V124
4 x/ e% Y+ C' D5 [125
# d9 P1 |' I& v \! g126" X+ N* ~: f" S$ ^* x3 A
127
! f+ a/ L! L' Y, Q1286 B) J1 S' c3 @
129
. `0 b6 ]1 s) s5 @8 w130
& ~5 Y. ^ f1 D4 W: d1314 W9 L4 g- f2 }# Q' _
132 ]# L8 [- p; I
133( M* i! O, v5 n; W6 @1 r. [' c
134
) b2 ^% ?' ~7 l135
6 J0 @# u+ D3 {+ i# L5 x136
0 ^4 c* l5 ^1 K% F137
$ b5 r" H# y& c0 O* i2 J6 S1 e1 b1 V138
. N' M7 A: b4 W7 k' ^5 t- _139
( ?( }7 {' ?4 u. K140
4 U2 i/ b3 T: M; \+ S# H141
) Y# K5 w7 F; [/ U142
Z* c5 o2 x6 {- ]143
! h! l1 }2 a. x0 d" I3 P- _+ O144
5 b1 z, r$ ]# N5 t3 N8 S' n6 j145
1 B ^- q! P% p$ T$ w146( ^! F! k @$ l
147
\4 Z6 n0 _- h# \% p148
( x3 Y8 Q3 U% f- i149/ ?0 U; V- e) _! g* L/ k" \$ u
150
/ j' m# F$ p1 R" c& d1510 O1 _1 I1 W3 c
152+ ~# I9 Y! h% h3 i* x1 C/ ?
153+ f5 j3 ~. N+ |4 j
1544 K" k3 }: a r. F( y" g
155+ g0 p. _; M* t3 L; S5 B
1566 \/ B) G: J6 j
157- H: P8 f! o2 q! _+ Q
158
# _, H3 g4 ]% M. v$ G/ X$ `0 T159
2 C9 U( `: I; Q% \0 B6 Q, i+ N160% x. s2 o$ X+ u) a1 t- H
161& O; D. ?$ A. V' K
162
5 E9 r; J) M$ W' J之所以把___Solve_oneTest()單獨寫成一個函數 而是放到main函數的for循環裡面, 因為: 當我們要進行特判 比如if( N==0){ cout<<"YES"; return;} 這裡的return 就是結束當前測試, 可是 如果你放到for循環裡面 你可能認為 那用continue不就可以了? 錯誤, 因為如果你內部還有for循環 這就出錯了 即此時continue不是對*外部的for循環*生效; 所以 必須要寫成函數形式; E9 ?5 u! _7 E1 m
1 m. U2 u5 _4 u3 l8 _Global_Initialize& x" J4 G$ E# R- D. j9 r u) z
专为力扣设计的, 即全局(多组测试数据所共用的)数据的初始化;6 r) m9 i3 n2 c
4 A/ v. i; J# \ i/ M
String
8 P9 B L7 y9 e: ESplit的答案 一定不会有空字符串;
, s: m, \4 `- w; [+ {" S他是从前往后贪心进行的, 比如"xxx" 以xx分隔, 那就是[xx] x 即答案是最后的那个x; 比如"xxxx" 以xx分隔 那就是[xx] [xx] 即答案是空的;
8 g, m, _7 Y+ ]6 {! H- X, O
* ]6 ]! X' ^+ T! s' {4 E( n% @@DELI;
4 z, p+ B z; M, _) a( c) q2 d. Y* k$ \ y
Replace的本质 就是Split函数, 即比如你Split得到的是? X ? X ? (将X替换为Y) 则答案就是? Y ? Y ?;: p( I7 C8 I/ X& w
. 比如S="xxxx", raw="xx", new="x", 那么答案是xx, 即先是[x] xx 然后[x] [x]; (并不是[x] xx 然后[x] x 然后x);- [* x0 u2 D. G. X& {* s* K
. f x4 F* l& G# N
Debug
7 e6 }' j2 l# {& y- I$ Y8 o9 h2 Tif( ?){ Debug::__IsOpenedDebug = 1;} 和 Debug::__IsOpenedDebug = (?); 这两个 是不同的!
6 o$ ?) u+ S4 E8 C3 e5 B/ w0 ?( |) Y前者: 他是在特定情况下 打开调试, 但是他不会关闭调试; 而后者: 他要么会打开调试 要么就关闭;# V5 r/ G5 b, y$ p( Y
前者 通常用于 针对某个子流程而调试, 比如... [T] ... 最开始我们关闭调试, 然后到[T].入口时 打开调试, 然后到[T].出口时 关闭调试; 即整个过程 我们就调用了三次IsOpen = ?命令; 这通常在DFS时 使用的较多, 即符合某种条件时 进入某个DFS分支时 打开, 然后回溯回来时 关闭;; M$ ]# y+ f5 Z$ U$ K% P; D; Z
而后者这种方式(即不停的根据条件 打开/关闭调试), 一般在非DFS的场景(比如FOR循环)里 会使用, 比如只对所有奇数进行调试;- U/ O2 E$ D2 l+ `, B" J; P' T
即前者 他是针对一个连续的子段, 而后者是针对一个序列里 满足某条件的若干元素;7 a7 h( M0 J; H: `/ D
( |! a; @9 D$ O6 p/ ^+ O@DELI;
7 ]0 s% C0 T8 D( L5 L) S. y5 @; a8 X- T. Y1 v/ N9 Y0 L! d
有個疑問: 為什麼要把他轉換成string 而不是直接cout輸出呢?! a3 T N: t4 C& _- d S
. 可能是多了一层封装? (但毕竟你这个模块 就只复杂Debug输出啊 有必要再多封装一层吗?
: u; R1 M2 O8 b6 k
# n# h) }& c& R! B@DELI;, C6 W. V; Z9 t
2 N4 \9 R+ i! I6 K( y: o+ X. ]; }INFO_里, 不可以对#__VA_ARGS__直接用,逗号分隔, 因为他可能是INFO_( F(a,b), 3), 所以你还得判断括号;
8 y7 P6 R) e9 P% L9 c
5 W# q* g$ G5 h/ A* i5 K: i( z@DELI;
$ K7 ~( Q4 `/ I5 g" \- k6 K) t5 z3 B
" T; U& z6 |9 ]" L9 y" ]& G1 U# CT A[10];數組類型, 你可以直接輸出DE_(A);. P, y. s# }7 F6 N% U8 Y! S8 V
DE_( (T(&)[5])A); 這是輸出A[0,1,2,3,4];
6 O: M: Y8 k8 Y3 `
6 _/ | M( z6 X5 y, E0 A. Zauto A = new T[2][3] (此時auto == T(*)[3]);/ s/ k2 Y" P/ ?& N+ C
. 要輸出他的所有元素, 此時直接DE_(A)是錯誤的(他是個指針地址), 正確語法是DE_( (T(&)[2][3])*A), 注意 *A的類型是T(&)[3], 但你把他強轉給T(&)[2][3]是可以的;) z6 V' Q9 C/ f* d) E
q1 h' q8 F: e6 r- i9 j( o4 U
@DELI;1 R1 h) }, a& D
J6 b: d2 \1 ] M4 a8 p__Debug_list的參數 必須是const _H & _h, const _T & ... _t引用 不能是值傳遞;
6 E0 W4 ?" |: l7 M比如對於對象很大的情況(圖 本身都已經1e6級別的大小), 那麼 這已經不僅僅是效率問題了, 因為參數用的是棧空間 這是會爆棧的;
2 r- J7 `+ |0 s& [8 t- W. m. \% V5 ]2 i0 d% l4 f! ~; ^
@DELI;3 [7 m" E: R9 U/ M! Z8 p; I' \
8 j" V' `3 a; U
我们使用__Cout自己的重载函数 而不是去重载operator<<, 一个原因是 对于char/string基本类型的重载 此时和系统的就冲突了 (你需要再单独写个函数使用is_same去特判) 所以 不如就不使用系统重载符了 直接自己定义函数; 第二个原因是 其实把 两者本质都一样 我们自己写个__Cout函数 等于多了一层封装;
8 X6 |4 _/ r: z }3 ~
% _0 v; b, A# W4 A2 i你必须要声明/定义分开 這是為了實現對嵌套的輸出, 比如对于vector< map<int,int> >的输出 他使用了Cout( map<int,int>) 因此 你必须要有其声明在vector實現函數的前面;* d! j, C. V5 ?' A& h8 ?& _5 C
; f/ {6 I; z/ h3 w7 u4 J如果是自定义类型 他会进入到Cout( T) 然后调用cout<< T, 即你的自定义类型 需要有重载运算符;
* E- o$ } C9 Z- R9 |$ ?; G
( u8 g: v7 c; Y& C; ]) R4 g% W9 J@DELI;
7 p4 o y1 Z1 R9 X; s, v# F6 X/ o5 B
+ a, g& B8 E1 D; c__Cout你不需要寫成 像ostream& operator<<( ostream&, T)那樣, 直接寫成void __Cout( T)即可, 這是因為: operator<<之所以要那樣寫 他是要實現cout<<a<<b<<...這個操作; 而__Cout 不會調用__Cout(a) << b這種操作;; A0 M/ O; h- s% f1 r. {) R8 B+ i/ o
+ ~1 B1 y( \. }3 f9 c) Q' w
ASSERT報警宏- J, U' d% b) y
#如何关闭某个子模块的ASSERT$
0 \7 m# A' h* [: \% N8 t对于算法模板A, 他里面有很多ASSERT_SYSTEM, 为了优化效率 如何把他们给关闭掉呢?' V6 p: k; ?& ^
* a; V$ O1 ~* ^8 t# `; O/ j/ A#undef ASSERT_SYSTEM_
+ u' T6 X6 S4 y9 f; ^) E+ r' h#define ASSERT_SYSTEM_( _op, ...)
/ H" i4 I* ]/ u E; X5 ~ namespace A{+ ]7 S- @3 h- A# e: b+ U
}( o0 G; W2 B0 z K i% F* h
#undef ASSERT_SYSTEM_
& [! Z8 K9 V- p" E% ^) k#define ASSERT_SYSTEM_( _op, ...) if( !bool(_op)){ std::cout<<"Assertion_Failed(System):["<< #_op<< "], Hint:["<< ___SUPIMO::Debug_::__ToString_items( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< ")\n"; EXIT_;}
( U s) L1 W8 l" o1
/ z3 p! ^% R, C* O25 R; U" M8 c# t% q
3
& e# `- }2 Z& Q( f2 l& F$ ]48 [1 E' z; b# ~! {0 A
5
( W) l# x1 P9 B8 `6
m( S3 C: Z- d7 W# m) _+ i- @1 ~5 d. 也不可以不写#undef, 但他会有警告warning: 'ASSERT_SYSTEM_' macro redefined; Q9 V3 ?7 z8 Q
: V+ P8 b% C2 s/ J2 R& d@DELI;3 K3 v8 D* M. H, o* e e, A
; B) w( A4 `, X
ASSERT_CUSTOM_: 用戶自己的程序裏面 使用這個宏;
, F) S) |1 E! F" qASSERT_SYSTEM_: 算法模板裏面的報警 都使用這個;/ {% a4 J6 u8 _( p/ o( i8 K# j
# X$ K: Q- j$ e
宏0 S) z$ V3 [1 B+ i4 R1 D: g+ \
為什麼FOR_的宏定義是 (int)_r呢?
% }+ q! @( X; e( L7 v# I# i+ C對於uint32 a = 0, (a-1)的值 是111...111, 於是for( int i=0; i < (uint32)-1; ++i) 這會死循環的;
. S8 v" J$ k6 c* e/ d7 O! n/ ?& W但是 把111....111 強轉為int, 她就是-1, 即int i = 0; i < (int)-1; ++i) 這是正確的;
7 `5 Z0 F: m5 [5 O& K
& B% l; x! q, Q@DELI;
; F* s% u! E4 D* E8 E, i7 F/ T" M
8 ?% t$ K+ m4 W/ y4 [這3個報警宏 都有2個模式:
9 M9 [6 p, s/ B# @ s$ J1(默認模式):[如代碼所示];& s, F9 J4 R1 D4 R& b* F0 ~5 O- j
2(優化模式):[你自己把他注釋掉, 這主要是為了(提高程序效率/便於找到程序BUG)];8 S! w: x& Z0 Z) A
. 比如默認版本是#define A x, 那麼你就把他改成#define A (void)0 // x, (注意後面的注釋// x是不生效的 預編譯時會被清除掉 即到時候是(void)0; 而不是(void)0 // x;)
- h; f) C; U8 E) w4 ]8 p! x3 P/ {2 H( x. X: J
ASSERT_MSG的優化版本 即static_assert(false), 此时在开发阶段就會報錯 也就是你會發現所有的調用ASSERT_MSG的位置, 就可以发现有可能存在的错误;
! F; @. z" t9 N I" }& D/ S3 v, A0 J8 p0 ]7 W! q
@DELI;
0 n" F3 u' Q* S+ c% g
4 b5 T% r$ d2 {+ ^- X6 `1 z* i#ASSERT_MSG_( _msg)#
: s4 n0 N/ w$ \& n/ A, b& X; k这是完全给用户提示的 程序无法测试其正確性 但你自己必须保证他是true; 比如取模除法 mod必须为质数, 就可以是ASSERT_MSG_( "mod必須是質數");$ ~9 F4 }+ j6 c4 b
: b/ z2 b1 I& w6 a2 M) L: Y
@DELI;( p4 Y: L. S; v! Y
4 P* f. H; ~# Q) d- ]: H
#ASSERT_WEAK_(op) (void)0#+ A# Y2 j4 w; p9 c1 X+ W! A
即使op为假 也不会报警, 但你自己要保证他一定是true 这是为了效率;9 m$ l& `' J1 G, a% [7 ^6 ~
, z3 i# W) n! WModular
: G6 x; W' z9 w' H a( eModular的設計思想是這樣的, 她有2個模式: 對於using MOD = Modular< T, X>, T必須是有符號int/int64/128;
- S% n$ T; [3 o- f1: 你的Mod模數 是不變的const常量, 此時 這個X是常數, 即在編譯期 模數就固定了;
7 j) _: E+ Y' {: |2: 你的模數 是可以改變的, 此時這個X <= 0(你任意設置一個值即可), 此時到了運行期 你可以動態的通過MOD::Set_mod( m)去設置他的值 且這個m參數的值 即模數 她必須是在T的正數範圍;
0 N- O) G) n. z$ T, C6 U3 _不管哪個模式 假設你的T=int 你最終的模數 一定是在[0, 2147483647]的範圍內的 (而不是uint32的範圍), 而且你的值Value 一定是unsigned T類型, 為什麼要這樣設計? 因為 當你進行加法運算 此時 你不需要轉換為int64 她的加法結果 一定是在uint32範圍的;
( W+ x6 S. F& ]8 L
T. V' W( Y9 g' N2 f; F5 e" P@DELI;- T# U, K8 p' P @- m$ n4 I. q
5 d2 g. `$ Z1 b8 u6 T& I
對於乘法操作, 如果是int32/int64 則直接轉換為int64/int128來進行乘法, 否則對於int128 則執行二進制乘法(她會調用取模加法 是不會溢出的 這就是為什麼你的模數 必須是有符號範圍);
3 i: I% ~1 T' ^
) [3 }& V, E/ ?3 \& J@DELI;
0 U7 ~/ }3 V" a/ V" G& x
, B2 K w2 X9 X' f1 {" Y6 l gtemplate<class _T> Modular( _T _v)這個構造函數裡 你不能對他進行is_integeral的判斷, 因為對於__int128 他不滿足條件(可能未來編譯器會支持 但現在他的返回值是false);
9 d' k3 P5 Q2 J% W
3 q# a% Z0 @4 l@DELI;
3 l+ S3 C: B8 u7 G+ Y T/ t9 M8 K/ V" M9 x
基本使用) e; Y" }4 S1 ?7 j
1 X/ q6 i I! I D5 O# z# Yusing M1 = Modular<int, (int)1e9 + 7>;% o& A% n- S# Q$ F6 z
所有`M1`的對象 他的`Mod`都是*int常量*;: r6 x0 ^3 r+ d# H/ k H
' z" L" F+ k3 \ i; E( i* g
using M2 = Modular<long long, (long long)1e15 + 7>;
( c3 D1 U+ B- V$ H7 a2 T0 F所有`M2`的對象 他的`Mod`都是*long long常量*;4 t. f+ y, c+ N
, s- J3 f8 F! }7 ]- \+ p I+ y
using M3 = Modular<int, -1>;' {. i: m1 _4 j* R- F! @
M3::Mod = ?; // 由用戶錄入 (這行代碼必須在*運行時* 即放到函數域裡)) s1 _2 N4 |: Y/ W2 S
所有`M3`的對象 他的`Mod`都是int類型 且等於`?`;
1 Q: q" q3 W- C! |9 b+ J6 _. X. ?/ ?3 \! W) s; S. B
using M4 = Modular<long long, -2>;4 j' R: H. c+ Q+ B0 r& u! `: W; B
M4::Mod = ?; // 由用戶錄入 (這行代碼必須在*運行時* 即放到函數域裡)
2 x7 t) B6 m6 K所有`M4`的對象 他的`Mod`都是long long類型 且等於`?`;
% g8 \" s: R! a; V
3 Z1 M4 f% m7 [2 iusing M5 = Modular<int, -2>; // 注意此時要和`M3的<int,-1>`區分開來 即不能寫成`-1`, 否則`M3,M5`就共用同一個`Mod`了;
1 y7 K4 F3 |& N/ @1 [8 \
( c6 ~8 \7 L9 ?7 }) R1 ]/ C' \ T3 Z& W
@DELI;, u5 L3 ^4 }7 Y [* A* O. j
4 u# { \/ F6 o, F; T* K3 E& M8 mT_ Value; // 一定是[0, Mod)范围; 不要调用`obj.Value = xx`(他不是规格化的) 而是使用`obj = xx`;8 e7 J8 E% e. G% |1 C
1/ b+ G/ G8 s0 `& O3 x
#除法## w& S( g$ O+ ^& g- U0 H0 O* ?
调用a / b的前提是: (1: Mod是质数), (2: b != 0);
% h, G3 P6 d- q6 x% V: ^) W
8 }4 }/ W! H! I8 w- W2 L@DELI;
5 G8 {0 |+ V' [( B4 P( v" w1 |, l+ x |0 C+ u& J# k/ M
#BinaryMultiply#
7 f, k7 b/ Q- i* S6 }9 o使用a*b(重载乘法)的前提是: Mod * Mod <= INT64_MAX; 如果是Mod+Mod <= INT64_MAX 就不能使用重载乘法了 可以使用当前的二进制乘法;
) [3 |/ W5 ~2 [3 B+ T2 g, F, N' B5 A% O4 G( ^
@DELI;
, b3 @3 j. O. L6 O7 H% M) {, ^2 v# @ j/ y& p
#__Cout#$ Q+ |6 K c5 ]- w
这个函数的目的是: 特判, 即对char/string/const char *的输出 重载, 之所以不是放到<<重载运算符函数里, 是因为 如果是<<重载 这些基本类型 就和系统cout的内置重载函数 冲突了;4 o! Q: Q- }! a( _
也就是, 比如对于vector的重载 是放到operator<<里的, 而对char的重载 是在__Cout里;
$ _8 b+ E6 a# D* r
3 o; c' m( W0 C$ |函數
$ m7 }' S5 g3 x$ V6 n#IsInInterval_#3 l. o. L1 x- J2 x4 R
. IsInInterval_(c,l,r, true): 判斷是否滿足`c>=l && c<=r`, 即在這個區間裡;
, U/ ^# @0 r! h/ Q. IsInInterval_(c,l,r, false): 判斷是否不滿足`c>=l && c<=r`, 即在這個區間外;
3 @& q( V4 D, ~0 z1 h: G1$ _6 s1 y3 m; C# X0 q) J+ J) g+ k& n
2, m, J- J* C1 Z5 F6 K( I( Y0 v
3& V8 N" f4 }" r5 }; _& `! k, O
Integer2 n; s o8 q7 i( E1 f
GetPowerRoot( a, p), 比如令T = a^{1/p}, 则返回值为T的下取整;
' [ D0 }7 A9 o0 t8 s9 a# J
; H) u& {5 N4 D4 v6 S@DELI;
/ Z% `2 R/ U' r Y; D! g3 q- o& W- d+ y C
VectorToInteger和IntegerToVector是互逆的;
# c8 m$ ~3 n4 @. D! T數字的高位 就對應 Vector的開頭; 這樣設計是因為: 對於一個整數321 我們通常是從高位開始閱讀 因此高位對應vector.front();7 K3 l! b J1 F
. 比如, 整數321 (3是高位 1是低位) 她對應的Vector是[3,2,1] (3是開頭元素);% r3 t) Q \0 T: [
b' x1 j4 }% A5 \. ~4 |@DELI;: V$ u$ G% x* O) E$ _2 K1 m
$ s4 R9 |; j5 I1 d8 {
使用该模块里的任何函数 都是谨慎, 最好就是在调试期间调用, 你要充分考虑好他的实际效率问题;8 d' v* y% |2 m+ Q# a" y$ G% l
比如VectorToInteger( {a,b,c}, 5)这个函数, 其实 你可以自己手动写成a*5*5 + b*5 + c, 没必要去调用这个函数, 因为此时你已经得到了{a,b,c} 他的长度是明确的 去调用这个函数 反而效率非常低;
! S( q% E5 f ?% D* @
8 X) k! h+ v2 T; z: e@DELI;6 T0 L! I+ c, T8 m) B& k
. j+ n: e/ m9 X0 R! `/ cvector<int> IntegerToVector( _T _a, int _len, const int _radix);9 f! W; J( \! x9 j* D
比如a=10, radix=2, 他對應的2進制表示為1010, 那麼此時你必須保證len>=4 (否則會報警);
; P* l, U' j- I1 |/ a8 ^! Q4 ?+ T5 J. @IF(len==-1):[答案為[1,0,1,0]], @ELSE(len!=-1):[答案為[0...0,1,0,1,0](即前面補充前導零 答案長度為len)];4 }* V0 _/ N8 _' T5 F8 |
( l& R2 b" L) C% a: N3 |7 @" {2 O2 b% }@DELI;
2 C" C7 E2 b# m( v( v; O& P7 {* Y E2 A5 B
Sqrt( a, p)
+ j$ R, N: H0 Q' i% d$ _9 q要確保a>=1, p>=2, 假設答案是浮點數b 且返回值是b的下取整;3 F" k- @' ~4 ?3 S
這個函數的主要目的是 判斷a是否是p次冪 如果是則返回其p次根;
6 F4 \" H; P& O* z4 Y. {. 由於b = pow( a*a*a, 1/3), 此時b可能是a-1/ a, 而答案是a, 所以要判斷 是否b+1 == a;
4 d" q1 x$ G: b2 h0 H5 X( F* ~/ k/ f, _. v' D" F
@TODO3 P, m3 @2 \) D- e$ Q# E8 j4 d- M
Modular里面, 我们用unsigned T来存储结果, 但实际上 你的取模值 一定是[0, T)范围的, 即只使用了一半, 这是因为 当涉及到+-时 此时不会溢出;1 i. |0 e5 \4 `/ D) F
. 但这有缺点, 当你Modular a = -2时, 此时构造函数是-2 % 5 他会变成int % uint -> uint%uint 即-2会变成uint 这就出错了!!! 因此要写成int%int;5 B) C0 v( h' T/ E) W2 x6 {
最好是, 你就用T来存储结果, 当相加时 他虽然会溢出 但其实他还是正确的! a += b; if(a<0){ a -= Modular;}就可以了;( _. d4 w$ S: g2 U$ C6 n2 M2 s
4 s" P3 g' w# D% [5 B+ x
错误& s8 Z1 F3 w# z: [
is_floating_point_v< Double> 他是等于0的! 因为Double是我们自己的自定义类型;/ y( h# U' m. l' V- L$ P& M1 Z
你可以写以下代码后, namespace std{ template<> struct __is_floating_point_helper<Double>:public true_type {};}, 此时 就可以了;
5 q3 a. l; d& k' v& G
7 k3 t: e4 E/ r/ a; N/ P' t算法模板编写规范. a* C9 P& V' K0 e" Q$ R# N
错误# j: ]( V8 C6 s, S
模板类 不要写构造函数, 因为我们可能写到全局域里 ST s(而不是ST s(??) 此时不能有参数;
7 M! V7 z0 L* Q4 s0 B* b4 y" c7 ]+ ~0 t. h
@DELI;
f9 m# b X1 m- Y# I' Z* }5 M# n
不要写namespace ST{ using T = ?; vector<T> DP; void Work(){}}这种代码; 这样会导致ST是一次性的 即T是唯一的; 然而namespace不能加模板;- Y d& y8 x$ b& y. Y5 j J
一种做法是: template<T> struct ST{ static vector<T> DP; static void Work(){} };, 但这样有2个缺点: (DP需要在类外定义 因为他是static), (由于ST是类 而实际上 他里面都是static的 不会用到他的对象 这就违背了类的初衷了);
) L2 Z% f4 ^1 P: C7 V" Q最优做法是: namespace ST{ template<T> vector<T> DP; template<T> void Work(){ 使用DP<T>;};/ ^! L/ V& @- Y, W4 A# s
0 `$ ?$ [8 ?+ U3 ?1 `5 Y
性质
/ ] e, o$ {7 p+ F模板类里放大数组constexpr int N = ?; int Arr[ N]; 等你用到时 再把?赋值, 这种方式 他确实是效率比vector<int> Arr要高, 但有个缺点是 你到时候的类对象 就不能放栈空间了 需要是static ST s 否则大数组就爆空间了;
5 b% w5 L* \+ Y* }3 b& s1 g1 Q: m A% X" `+ e' y, l
@DELI;5 S) `1 \4 I) d" @- _
: \+ Z C! W2 J v不需要寫一個TODO_STATIC_的宏, 對於靜態的@TODO, 你直接寫成注釋即可: @TODO: xxx, 然後實際使用時 再把他給注釋掉即可;8 [ r; j6 `, @; H* ^9 Z
v. g4 i6 E3 O/ s. y" E@DELI;; g8 Q; D' _/ N
9 S6 f& q# B' ~& @5 [9 r$ T7 y3 V#讓某個函數 必須在程序開始後執行一次 且只能執行一次#$ ~8 A1 }! y; x. u* [1 w7 j
e/ i, K, ?. X0 I' V3 K. D% S- m$ j
void Init(){8 _# \4 E8 f# K
EXIT_COUNTER_(2);* T" P" M9 e' U7 J4 e
} ~" \% J; r" y/ p
@TODO: Init();- @% n. K( u7 u& J3 {0 C# s+ W" i& I
1# m8 ^. ?# U9 K1 A! ~
2
2 v9 q! }! E" i$ O8 M2 h; y3" D% J+ j( f% S' `6 v
4" P5 J6 Y& S0 k0 n8 [9 u! `
這類函數 通常是不可以有函數參數的 (比如篩質數函數), 也就是 她的參數 是根據題目的最大數據範圍 而不是錄入的值;2 |9 Y" L) n1 u! E+ Q7 r# s% M% u
: e2 v+ p5 n% P; |$ T) W9 W不要用__attribute__((constructor)), 她是報錯的, 因為他不是在運行時執行的, 而我們的需求是在運行時執行;; c! K0 P, ]) f
; f* u+ c% e8 e3 f& f% j@DELI;
" n% O5 z+ h0 h7 g& i/ a# Y
1 o* ^$ V; `. O( q( T5 W7 u#類/命名空間的Debug調試#
% V' P. V5 `7 y( }1 m
2 ^ v. y5 a4 w/ Z5 U+ F$ Yclass ___X{
l9 F& j% R' z! n5 L" Y friend ostream& operator<<( ostream & _cout, const ___X & _a){
; w+ P% I1 b+ ]/ |- d; n6 y6 ^ _cout<<"\n";
5 J& a1 @. d( T2 l DE_( "___X-Debug-Begin");
# P; e" i! {5 K+ n0 q1 i3 [6 Q+ k: L# ~9 u* M$ L
cout<< ?; // 此時不可以使用`DE_(?) 或 `Debug::__CoutItems(?)`, 必須使用原生的`cout`;8 s" j3 v/ P9 m4 k+ ?
8 ~( I0 {& Y3 m. ^3 Z. L8 @
DE_( "___X-Debug-End");
a5 {1 y$ K5 Z" j }6 a! |" {3 Z z. I! s! L
}) i% ^) K' o0 D& X$ y' O& m" @
+ P% o5 v! W6 L' u8 Znamespace ___X{
: a7 W* h# k$ }) Z void Debug(){# c- e& b* U* @1 B3 b: {! k2 a
DE_( "___X-Debug-Begin");
$ X+ v- n# E3 K! d
3 C& [7 |( D0 n1 q$ z2 r7 g; A* z cout<< ?; // 此時不可以使用`DE_(?) 或 `Debug::__CoutItems(?)`, 必須使用原生的`cout`;
2 x) I7 R! D5 K: m2 W; Z4 n/ T. M/ V5 m0 t3 P2 Z4 U
DE_( "___X-Debug-End");) I, ?) O6 G6 \9 M
}/ G: R2 t; T3 `& c, X; B( _
}
# t, y' y' }% q/ ?! P3 n
. i6 Y# q4 }. Q# d, ^( o0 s& u' U o@DELI;# G4 ^/ q# p9 F* `( y9 L
9 u; E1 B8 x* F( ^. v- S b
#嵌入模板的全局变量#( ^( y$ A) O# q) }8 h
5 o! Z- [& M/ ~- i+ u{ // ___XX0 ~. q! d3 ~2 O; D6 |$ B" x
const int ___Number = ?; // 这里就叫做全局变量; 要以三个`___`开头+ O( J; a: J% V5 ^" ]
int ___N = ?;
: X$ K+ `/ G1 L b3 [ for( int i = 1; i <= 5; ++i){1 o4 t; w- O* i0 N* ?6 N& f
int a = ?; // 像`i,a`这种*临时变量* 可以不用写`___`开头;
$ l( o0 x; B m! G- b' l }- O, s; Q5 Q" H$ k( s9 S1 i; r9 u, L
" ]" I7 e1 z9 X u3 W* f6 [6 B
} // ___XX5 `- ?/ u) k3 w5 x* u0 I4 C! l
7 T! \7 M" v% n$ i* v
@DELI;
1 `( l- \/ m$ P) n1 i% t! P N' r3 b, c: Z& d
#Initialize函数, 强制的放到构造函数里#) k6 i9 ?: x& K3 h6 E) a' O8 _
最经典的例子是(建图)* D+ u$ e' X7 D& o9 {
- P2 e. |* P" K+ K0 {Graph( int _points_count_maximum, int _edges_count_maximum){}9 h5 b |+ t8 F/ ?
void Initialize( int _points_count){}" S9 n2 @! p2 j( r# v) q. A# }# r
1! x# L: g8 G9 ?: S4 `- z$ M
2) _4 ]) j* X% w' V1 L0 _
这样分来 会导致, 每次使用时 必须是: Graph G( 100005, 200005); G.Initialize( n), 也就是两个代码行 (两个操作, 两个步骤)" q; {4 |0 y2 k
一旦忘记手动的调用Initialize函数, 虽然会报警, 那你还需要再去写代码 补上调用这个函数;; Y, Y! Q! \4 V4 i
5 E9 i2 C9 e* v6 d- b
当我们将Initialize函数, 嵌入到 构造函数 里
3 N% C8 q2 K+ O, b5 a$ A1 c3 u: Z% U4 x8 L9 { M! }
Graph( int _points_count_maximum, int _edges_count_maximum, int _points_count){
% v8 j$ Z5 Y4 o7 D: u. q5 M ...
T+ {2 ~: G0 ^$ e3 t: ^/ z1 ` //--' s$ m, g- X9 p7 v1 |
Initialize( _points_count); {6 V7 M3 ~) P3 }) _1 e
}, R9 E7 f! U6 x9 z9 r8 G
void Initialize( int _points_count){}
m/ Z* N' k8 r$ B) t3 h) {
, q8 I0 `9 |8 ?/ s) z9 \注意, Initialize函数和原来是一样的, 只是做了两个事情:& C9 V- F+ M5 h" Z; G+ S
1 将Initialize函数的参数 接到构造函数参数的后面 (比如, 原来构造函数参数是a,b,c, Initialize函数参数是x,y,z, 那么现在变成构造函数参数变成了a,b,c, x,y,z), B$ K! t$ J8 n% Y9 R' _
2 在构造函数的最最结尾, 调用Initialize( x, y, z)函数; X; H/ O: s# d$ X: W9 |
8 |, t# T- @/ `/ B; g! L
@DELI;" ?) F( Q. t: ?& f+ c$ }( k
1 O+ I1 T9 S+ ~: G
#数组长度用函数传参来指定#
: v* Z1 q* F1 `7 U' u, x
3 y. Y& ]9 L# d o9 n: I+ ?' Etemplate< int _Maximum>. B& s; `- F$ {5 k" W: w7 v
class ST{! ?+ L2 @2 K2 U t
ST(){7 o+ o( P9 }$ g7 F
array = new int[ _Maximum];
5 c( g, B" X. d: u }
( E! ^4 C# G9 ]& }3 m3 X+ Kprivate:, n& x7 S F6 o; ?* {0 X( f
int * array;3 k4 _4 A6 G: Z! d* l/ T( W) r6 W
};$ i* O, y0 z N& r6 B2 e( S$ C4 f
# g, ~# ^1 |$ M zThe above code should be replaced to:
3 ?0 }& e0 O. Z5 v! Z3 D# N7 T& u. b, c% p0 G
class ST{& n0 v" s' V7 i: I: @9 Y
ST( int _maximum)0 S c. }( E" U0 J/ n% V& v( L
:
: S4 ^" d5 H9 n0 q- ?8 R1 @ maximum( _maximum){
- R5 A9 h5 o& Y5 C: [; p% `6 w array = new int[ maximum];
# f1 J/ K1 @- Y9 q3 t }
& |6 M9 i# H& [( a, J; sprivate:
0 J! }, \, I# }3 I1 Y int * array;
5 F" }/ n) P6 z0 S const int maximum;
/ N3 Y4 ]1 `7 K5 V$ b: J};
- x) ?' K6 C# P1 P
* e9 `; r: x0 }3 C5 Q' q, ^& H@DELI;
: T2 O- Z' R* _; x! z笔记
" q1 e+ W5 C# i$ I有向无环图DAG
/ i0 p% o {: ?2 f9 f Q最小路径点覆盖
6 ]+ O3 }7 d {//{ @Snippet, `ZuiXiao LuJing DianFuGai (最小路径点覆盖)`+ _2 V7 i6 G {- y
{
3 a m: D! f) ?, R int n = `the points-range in the DAG`;
/ D: U- s+ b( m# v% E# m' u //--8 {3 m6 K8 Y/ _5 s/ B
BipartiteGraph B( n * 2, `the edges-count in the DAG`);( W4 s6 W- a' A' R5 x) G; Q! K, C
B.Initialize( n * 2);
2 x: W* Z8 b* V% N, s1 T for( int i = 0; i < n * 2; ++i){& o4 u. {( n( H J. x6 u
if( i < n) B.Set_pointBelongingness( i, true);+ B$ e( F& y7 _8 D2 n
else B.Set_pointBelongingness( i, false);
i1 F. u8 \- N1 @ }# H; X- S% L; B) _+ l/ H# x" }
for( `s -> t` : all edges in the `DAG`){
; l4 ^) ?! v4 F! q1 b/ @1 ]+ ` B.Add_edge( s, t, 0);6 @' ]; t! V. E+ w1 R) y
}1 I) g) [5 ]2 ~0 I
//--
: Z% Y3 s' }: o7 B5 U+ E Bipartite_MaximalMatch M( &B);
6 P& V% |* `8 z M.Initialize();2 a. @1 H8 L. F1 v( g! ~
$(n - M.Get_maxMatch()) is the answer;
1 r( _9 _' o, K% X2 L} k' M0 W ?: Z% I! }7 T
//} @Snippet, `ZuiXiao LuJing DianFuGai (最小路径点覆盖)`
: f. T, \: R4 q8 }: L3 s1 z. [6 Y1 [
最小路径重复点覆盖, 最大路径独立集: @, {. }! o2 D6 I% b
//{ @Snippet, `ZuiXiao LuJing ChongFu DianFuGai (最小路径重复点覆盖)` `ZuiDa LuJing DuLiJi (最大路径独立集)`
( n1 W5 B" ^+ I: | J l, O( I5 Q. M{$ F! N1 P+ z9 f% z, d
int n = `the points-range in the DAG`;5 [% W# u; B7 l, y
bool * edges[ @PlaceHolder] = $(edges[a][b] means a edge `a->b` in the DAG`;/ f: ]: C# N" C; G: @
//--
3 l& K. F e! A& w2 S+ T $(perform the `Floyd-Boolean` on @Var(edges));- T% x3 F# E% Q6 p4 M) \
//--
2 J$ M7 w& V3 x# K5 P BipartiteGraph B( n * 2, n * n);7 y4 y5 [* \/ b$ f4 W! G) w8 |3 X1 {
B.Initialize( n * 2);
% ^( Z; g ]: G; U5 C5 o# z for( int i = 0; i < n * 2; ++i){: Z1 O: O. A. q1 @5 @: e& i
if( i < n) B.Set_pointBelongingness( i, true);
, i4 x- d2 P( i else B.Set_pointBelongingness( i, false);
% | u ~9 e: g# d$ r" M( ? }8 w% k- [- J! ?8 o% ]) E; @
for( int a = 0; a < n; ++a){7 A, W) t* g* V. p2 P* }
for( int b = 0; b < n; ++b){
* W/ |; { E+ Y& x) h2 K9 K- ? if( false == edges[ a][ b]){ continue;}. I0 h+ U- `9 a, p# Z7 `
B.Add_edge( a, b + n);
4 k. P; { [3 ~( O) v }
$ a& ^0 s6 h- K/ B7 c }
" X. ?1 j( g7 Q8 c, d9 n s //--
6 B1 c! u# C+ `) ]% [+ z Bipartite_MaximalMatch M( &B);3 R& [& D3 Z9 F- S
M.Initialize();2 B1 ? q1 p6 E6 B/ u" m3 O# _1 N
$(n - M.Get_maxMatch()) is the answer;
9 r' ]' W; W/ J# [: V0 [}
' U! U: \ v" {5 r//} @Snippet, `ZuiXiao LuJing ChongFu DianFuGai (最小路径重复点覆盖)` `ZuiDa LuJing DuLiJi (最大路径独立集)`8 N/ a _) S' J5 [9 S6 @
' P! L, u. o( L8 O/ d! TDAG的终点- o0 q# v \/ A
//{ @Snippet, `EndPoints of a DAG`' y7 W' Y0 Z! Z5 U0 C
{
b' A& s& k$ J; ~+ Y int n = `the points-range of the DAG`;
9 Q4 i) q% G, R7 ?# M3 V; ^ int * departure = `int ?[ >= n]`; //< the departure-degree of a point;
' ^4 ]8 N6 @! q. D5 z* g" ? memset( departure, 0, sizeof( int) * n);+ q4 b- D7 h, k9 X& X
for( `a -> b` : $(all edges in the DAG)){/ q9 @2 ]3 x9 Q# K
++ departure[ a];# Y' [* ]1 I0 n- z+ z
}! a; M. t6 P5 F
for( int i = 0; i < n; ++i){
0 \* }* ]9 b8 _ if( departure[ i] == 0){
k9 `- O9 x2 k1 G' ~//< `i` is a End-Point in DAG
/ e+ _2 r/ J+ _3 K8 S/ o% c }! ^- M. n) c' D4 J. E: r
}6 N5 H2 S! X5 w# c6 X ?5 L/ H6 N
}# H3 x1 L4 e2 {" \* t9 B3 _
//} @Snippet, `EndPoints of a DAG`% H# @" @3 u" F) H/ s
6 f# q7 a' g1 K- Z
DAG的起点
8 s9 t! N# S- y$ }//{ @Snippet, `StartPoints of a DAG`' T# v- s' A/ k/ Z: s
{
3 D9 C) x: ]' r4 t int n = `the points-range of the DAG`;
: c _: T6 d8 i+ R$ |% M& T int * incidence = `int ?[ >= n]`; //< the incidence-degree of a point; g0 L* I q3 S: j
memset( incidence, 0, sizeof( int) * n);( O3 ~1 c, B* ^8 n5 X
for( `a -> b` : $(all edges in the DAG)){
* l" E6 d5 @+ m8 |; W8 _9 N; y ++ incidence[ b];
1 ]& }' [7 u6 a8 t }5 u" Q7 _& [; }" z1 b# a
for( int i = 0; i < n; ++i){2 K, P S9 K& F8 a* X
if( incidence[ i] == 0){
5 ?; `" Z# Y6 Y: C/ A% F //< `i` is a Start-Point in DAG
. |+ M. i) t7 B9 a' M& U }" P+ m5 z/ D$ |- \2 q
}& ~7 Q. r1 j) c8 W, l* f2 n: Q1 C
}- }% x5 \4 X( d9 M( u
//} @Snippet, `StartPoints of a DAG`9 M+ r( n; X' F9 M
}' y: z: d: Z$ g; F判断一个图是否为DAG, 求拓扑序* X% e' x4 U8 V- e0 X
bool Work(){
/ O* M5 s8 S4 o3 j/ C//< `1` Check whether a Graph is a DAG; `2` Get TopologySequence;
7 t6 W( [" L6 B/ i int points_range = @Unfinished;) V4 K6 `! r8 Y0 T4 j1 F
int * topological_sequence = @Unfinished(an outside array whose length must `>=` @Var(points_range));' N. K! ]& G% `! c
int * incidence = @Unfinished(an outside array whose length must `>=` @Var(points_range));1 ~1 B1 N& M c) C/ e. e' H' I( F
memset( incidence, 0, sizeof( int) * points_range);
* j) I9 ]0 T" \0 e% F1 H" T for( `a -> b` : $(all edges in the DAG){
6 k$ n4 v+ L E& { ++ incidence[ b];
% w- H- T6 ~5 v3 | }4 @7 J" k2 n+ P q5 o8 p
int size = 0;
# x/ K- `5 d: z4 z4 B9 e* @' { for( int s = 0; s < points_range; ++s){' @: `" M5 b8 i# b n
if( incidence[ s] == 0){
" D& O' V" Q2 K topological_sequence[ size] = s;
# p. L. F, }& g) ]7 J ++ size;9 d* h# Y: D8 j
}
8 w L! j# }/ u2 L( l7 l2 h }
6 i- S/ Y! F+ N# L3 M int head = 0;
: ?" A0 K6 ^0 \ while( head < size){# }( u1 i/ Q+ Y ~! P+ X, K' l" r
int cur = topological_sequence[ head];
7 P7 L$ s2 N+ d( ]! i ++ head;2 w( B2 z6 Z0 J, S! }0 F( M
for( `a` : $(all adjacent-points of `cur`){. |1 L2 S9 G. L
-- incidence[ a];
* ~) R0 S5 q- `( U if( incidence[ a] == 0){
( W0 B5 m0 e) f" x7 M% k1 t topological_sequence[ size ++] = a;
( P/ `7 W0 D B }
% J" ~9 p Q+ m; v/ N( ?' T }
" E! x) K$ \& N1 I }' u1 |1 s, d* B$ r' T
if( size != points_range){( _* C% K: h+ b# R2 P
return false;
9 i" L$ t$ O$ M- w6 c: x }
6 m$ H% ~1 G- h* W5 `9 r //>< The answer Topological-Sequence has been stored in @Var(topological_sequence)
; W. H% {$ ]! j2 R+ K. w: o2 h return true;# Y3 B# m/ O* t) M' L
}
5 h) N1 S, V! v. b7 G7 u; N1 K' b+ t/ C. s" R
图论
% T/ I A' t) ?1 M# H最短路% u8 g) |# t$ ]9 C8 x
TARJAN
9 O7 u) o. l% Q无向图-PBCC点双连通分量- I- Y. D# b4 e
+ 割点, y- ~' p, h @! o A
1 ?" i- V! I& @" x9 \* ]7 V
//{ Tarjan_PBCC-Declaration
* N8 A0 Q O- g0 @& \5 _. `# btemplate< class _Edge_Type>- `5 @- p3 \" P
class Tarjan_PBCC{
& l0 C6 u7 K+ S' qpublic:' ~) }5 B+ J4 @, `) X
const vector< int> * Pbcc;' { U7 F4 ] g8 z3 v: v f3 ?. s
const bool * Is_cutPoint;" A/ h" F/ r7 r! K( K* T+ U
//-- variable ends
6 S& N1 g* N8 G' k+ L1 l" ]5 M: [% W Tarjan_PBCC( const Graph< _Edge_Type> *);7 r* A! [( o+ }! w$ T
void Initialize();) Q& D) S: T& Q: \; F
int Get_pbcc_count() const;) G. S$ ? v5 R
private:
' E3 \2 [' ` ?' ~1 H const Graph< _Edge_Type> * graph;
: W4 Y F$ H( t* M" | int * stack_;
# H, \) O* ^# G int stack_top;6 \/ E1 F% D8 ~- a5 |$ O
int * dfs_id;
2 T% `( P4 Y, E2 i/ i# W6 g int dfs_idCounter;
4 F0 v, u- L$ M int * low_id;
6 d( W) T! P# O: \ vector< int> * pbcc;
: @3 u4 U" Y3 `. A+ c# ^ int pbcc_count;, ]3 E0 \: _/ |" ~' C) z% u! x. g) A
int dfs_startPoint;
% O: H4 r- W! s& v+ f& _) C: r bool * is_cutPoint;
- P- @" k4 p# ~3 M+ {1 D. L2 M; N5 } int cutPoint_count;
& Z8 Z* w8 H, Q. \ //-- variable ends
. f8 w: Y0 M3 c; E+ K6 g2 m void dfs( int);- ?# e& _# Y7 q' e ]# r
};
4 P E% r; U9 O6 u' H9 p: [3 }; ~) ^//} Tarjan_PBCC-Declaration
. z H* S! \) u' f
4 |6 P# a, b, R' |5 H' ~. w//{ Tarjan_PBCC-Implementation$ V% x5 f$ V; J! Z
//{ Variable-Annotation h& u* l( s7 d- O2 z
//{ @Var(pbcc)' [$ [) d9 M7 C$ i- w. L
// + `pbcc[i]={a1,a2,...}` means that the PBCC with id `i` consists of these points {a1,a2,...}, E3 B* L% z7 f
//} @Var(pbcc)& C! F8 G# G' G+ u, z0 O
//{ @Var(graph)# ` G/ _. `5 p
// + must be a undirected-graph, i.e., Edge[i] = Edge[i^1]
f3 |) U) R2 j$ |" z% K //} @Var(graph)
. \6 e9 c+ B0 n% t3 }- d$ o; h$ P2 w //} Variable-Annotation* Q r: B7 k3 w- B
template< class _Edge_Type> int Tarjan_PBCC< _Edge_Type>::Get_cutPoint_count() const{ return cutPoint_count;}
. ~4 d- i4 [4 C z- |template< class _Edge_Type> int Tarjan_PBCC< _Edge_Type>::Get_pbcc_count() const{ return pbcc_count;}
5 Q, K4 \& T ntemplate< class _Edge_Type> Tarjan_PBCC< _Edge_Type>::Tarjan_PBCC( const Graph< _Edge_Type> * _graph)
7 d: X- ~( d- T7 G4 B& y2 {9 s :
; D% _' x' n4 T) ]4 ~' D% X( { graph( _graph){
2 A8 B/ j) k+ ~. z stack_ = new int[ graph->Get_pointsCountMaximum()];6 T) J+ l; q) m; B6 {! I1 }6 _
dfs_id = new int[ graph->Get_pointsCountMaximum()];
! U9 z$ q% F% z+ J' {9 E/ { low_id = new int[ graph->Get_pointsCountMaximum()];! N: P+ t- C7 D+ q2 n9 i
pbcc = new vector< int>[ graph->Get_pointsCountMaximum()];
; m+ S( a4 ^; v% N" U is_cutPoint = new bool[ graph->Get_pointsCountMaximum()];* G' V! R+ x8 D2 v7 I
//--
1 F- Z' Q9 |2 s' F1 k% b2 s9 Q Pbcc = pbcc;
H/ v7 k0 {% x Is_cutPoint = is_cutPoint;. g4 _6 E2 d: a0 l( I; S4 \
}
+ _1 ^; R7 w* }) s2 z) T0 Wtemplate< class _Edge_Type> void Tarjan_PBCC< _Edge_Type>::Initialize(){
2 i# T3 N: W0 Z6 X \5 b stack_top = 0;
1 O# o" ~9 p- w dfs_idCounter = 0;
5 p w0 x3 o" L# X2 g pbcc_count = 0;
* c! Q6 {2 X" I' F8 F3 h' ~ cutPoint_count = 0;8 z' b% z3 W3 d1 x+ c
for( int i = 0; i < graph->Get_pointsCount(); ++i){ pbcc[ i].clear();}
+ a. I; \! A/ J) l" h& Q- E/ p) } memset( is_cutPoint, false, sizeof( bool) * graph->Get_pointsCount());
2 R: n/ T0 T+ \! z$ p6 H7 s memset( dfs_id, -1, sizeof( int) * graph->Get_pointsCount());
! G& R8 V9 B$ @ p+ H! D. Q for( int i = 0; i < graph->Get_pointsCount(); ++i){
) ^( Y3 D) i3 E6 x( R! G+ Z2 S if( -1 == dfs_id[ i]){8 H O% o! ~8 L3 k6 `
dfs_startPoint = i;
% v8 c* j: ^" A' o7 H dfs( i);, O) a1 k9 ~' ^/ L- R
}
3 a" I# i% w; I5 K1 Q* m }: \* G: {% T& s* R" j# O
}
1 w$ R" i+ f6 vtemplate< class _Edge_Type> void Tarjan_PBCC< _Edge_Type>::dfs( int _cur){
/ H" f' i; a! U/ d3 D' B& x9 ], j1 S stack_[ stack_top ++] = _cur;$ a9 J2 m0 f2 S1 l: d8 b( u
low_id[ _cur] = dfs_id[ _cur] = dfs_idCounter ++;
, c* \* [& `7 g& l7 H# q8 {$ Q //--
6 a& m5 b2 ?% g8 O int cc_count = 0;
- n4 N' Q! f, ~9 l2 e% O) s% Z) o4 y if( _cur != dfs_startPoint){ ++ cc_count;}
9 p4 M+ K& T# y6 l* ?7 J+ ` for( int nex, edge = graph->Head[ _cur]; ~edge; edge = graph->Next[ edge]){
2 `3 b$ u# j0 h+ v6 f nex = graph->Vertex[ edge];
" m/ J8 S7 M3 i8 P; b if( -1 == dfs_id[ nex]){
% c8 r ^3 G( l0 e& |9 P dfs( nex);" p& N" J( a0 A# Y- j/ [7 f C
//>< `low_id[nex]` always `<= dfs_id[_cur]`
. P7 N* N" P; t7 t5 |4 `. m, n if( low_id[ nex] == dfs_id[ _cur]){
0 C( j* D7 A- Z- K7 Q$ m1 U @: b, { ++ cc_count;
3 ]4 H3 ~! G0 R: d# u if( cc_count >= 2){6 H: b* G2 F" U( l) N
is_cutPoint[ _cur] = true;
( H7 F- X; d$ a6 ^7 F7 b& E* O- i ++ cutPoint_count;
9 w" g0 m7 N9 b T+ A, w& i while( true){. }, ~2 n V5 O( e
int c = stack_[ stack_top - 1];% m8 x' t6 I# @) g: h& Q, J
-- stack_top;
2 X/ t+ I f' V7 K2 ]. P 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.
8 o7 Z; z* Y( H! X; q7 W. [* D if( c == nex){ break;}% b) K" d9 h3 ^( h4 E% H; p
}
: G9 [3 l; O& A, h pbcc[ pbcc_count].push_back( _cur);
5 T4 @1 y4 k; w/ _) c* R/ F //>< `pbcc[ pbcc_count].size()` >= 21 r& X; j" c! o, X8 u
++ pbcc_count;$ V0 A. a: F$ [# L
}
r4 u' A |" p% _% w, z }
" [% X7 }% K$ B low_id[ _cur] = min( low_id[ nex], low_id[ _cur]);
; t7 D0 f2 {% q1 h5 v, N }- I5 N4 k1 M% \4 g
else{ //< `nex` must on the `stack` due to the graph is Undirected8 L9 k0 j; D# C( k
low_id[ _cur] = min( dfs_id[ nex], low_id[ _cur]);
* }" }6 h4 b5 b2 ]. l$ R }
' M. r3 H/ g$ n+ a; Q2 |" { }
, n! y* p; Y- m# a //--# h8 a8 k* l8 D! z
if( _cur == dfs_startPoint){5 I1 G! P( K- X) U7 U7 w
while( true){8 q/ w }9 c9 ]7 _' p) @/ @
int c = stack_[ stack_top - 1];
9 L+ h! l9 J; f -- stack_top;4 l5 D1 H! x9 ~0 N& u3 B/ v4 w
pbcc[ pbcc_count].push_back( c);! A9 f; K0 L5 l3 e/ N* ^1 S; b
if( c == _cur){ break;}
/ `+ b. z8 i& G4 p F" B1 c }
4 u' ] g9 [, M+ l! T: o$ ] ++ pbcc_count;
* @- Z3 Z/ ], \2 d }3 D6 i- H. P; u& l* y# N
//>< `cc_count` means the number of Connected-Component when `_cur` was removed from the current Connected-Component (whatever `cur` is Cut-Point or not);
% i3 J; f: l0 p% f1 Z/ p}0 [0 ^+ [9 D! c$ v0 F* G: {
//} Tarjan_PBCC-Implementation
" `6 N- B+ u4 Y) n0 @6 U }
! h! n% E4 B: M) G/ W! N& j无向图-EBCC边双连通分量
- n( _2 t3 i0 k, ?+ [# A+ 桥" K5 O' K7 q# [. q9 y* a
7 u/ _% [$ Y: X- v$ x; k# |
//{ Tarjan_EBCC-Declaration0 \/ U* _2 A5 x* I7 ]
template< class _Edge_Type>
. _3 p2 J) n% S% D6 Iclass Tarjan_EBCC{
# ?/ e& ^2 X" j9 z; A. z# Z& g$ spublic:$ |5 C3 _' b" M1 m0 Q: Q& ?' K
const int * Ebcc_id;* L' z0 l: J9 ~
const int * Ebcc_size;
- E( A/ {7 ?! Q //-- variable ends$ ^6 I" t9 W7 S3 z' r
Tarjan_EBCC( const Graph< _Edge_Type> *);: N" c* q0 d7 f0 G0 [" X" g
void Initialize();* ]1 K4 o' m9 J% U6 `$ N. Y
int Get_ebcc_count() const;
. c$ c* K* E* R* [ const Graph< _Edge_Type> * Build_tree() const;
7 |/ ?' j3 O( k. @- U, s3 iprivate:2 o3 A3 \% I6 S/ V( G8 o2 M
const Graph< _Edge_Type> * graph;
- f( \% A, O& M2 Q& J3 s int * stack_;6 ?: E# C4 U& V- x; }
int stack_top;
/ x, Q7 \+ F1 l' V" U int * dfs_id;
9 `4 s' b/ @4 Y" G0 j3 R int * low_id;/ L% H1 z. X, v! Y4 U
int dfs_idCounter;
6 u" o M" p% G3 [, o/ { int * ebcc_id;
4 O) `! L9 w5 H. O+ K! |# }/ ] int * ebcc_size;5 n& j4 `2 V' `4 R- p
int ebcc_count;
+ ]0 d+ S$ n2 c5 z# z //-- variable ends5 ~" K/ K) J; J) a; {
void dfs( int, int);& \) }, ^& M" x3 f
};
6 Y# M1 p: J7 U0 v//} Tarjan_EBCC-Declaration
y4 a3 T D3 [* x; C; v6 `; `" Q7 X
//{ Tarjan_EBCC-Implementation$ f% [- N, g( Y- [2 U: t+ t$ }
//{ Variable-Annotation
8 x* k" i& w+ R" y //{ @Var(graph), E9 K) j4 g) D% w- X# e4 }7 a
// + must be a undirected-graph, i.e., Edge[i] = Edge[i^1]
3 E7 R; c i+ V% }* c8 F ~( {2 U9 i //} @Var(graph)
8 g* t! b. E7 m& d3 D5 `3 m //{ @Var(Ebcc_id)
v" P1 G0 q3 \" y5 X7 i. p // + `y=Ebcc_id[x]` where `x` is a point of @Var(ptrRef_graph) and `y` belongs to `[0, @Func(Get_ebcc_count)-1]`
0 h1 `3 K0 w/ E+ ]( V //} @Var(Ebcc_id)% g7 T% K; d4 q f8 v; D
//{ @Var(Ebcc_size)
4 \) d$ C3 y3 d* z // + `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), L$ Y( M% t4 y% g4 }2 t, @
//} @Var(Ebcc_size)# J) h, J. K h- r, m3 u
//} Variable-Annotation3 G n$ e0 P* i2 Y/ N4 S
template< class _Edge_Type> Tarjan_EBCC< _Edge_Type>::Tarjan_EBCC( const Graph< _Edge_Type> * _graph)
# n( T" k0 O, E1 `4 q, W7 ]- |& W7 B :' h8 v" Z1 D q2 W8 E
graph( _graph){6 Z4 d. J2 z9 M o# V# T6 u
stack_ = new int[ graph->Get_pointsCountMaximum()];
- K0 B* Q4 D S& W2 ]7 z" ] ebcc_id = new int[ graph->Get_pointsCountMaximum()];& t' C6 T5 c5 `% R
ebcc_size = new int[ graph->Get_pointsCountMaximum()];0 p& U. B4 h7 A! U% d. \
dfs_id = new int[ graph->Get_pointsCountMaximum()]; W1 N" ]; d4 ]- ~3 ^
low_id = new int[ graph->Get_pointsCountMaximum()];
7 v1 E) }4 n0 d0 u8 d //-- g( Z Q9 r! [: {$ k! a
Ebcc_id = ebcc_id;3 d7 H! s5 x6 x) T2 v
Ebcc_size = ebcc_size;
9 i% [ {% n, s3 ?}
( u2 g. [) B! l, e. _1 z3 D7 otemplate< class _Edge_Type> void Tarjan_EBCC< _Edge_Type>::Initialize(){) ^2 P& D3 W4 D* x2 J& K0 O( O, o
stack_top = 0;
% T% X$ d. t/ d; w, j; |2 d% i9 S6 H dfs_idCounter= 0;' A4 e& h% h7 |5 T# R9 l: v% k/ W
ebcc_count = 0;- [0 {- l+ i( `
memset( dfs_id, -1, sizeof( int) * graph->Get_pointsCount());4 A0 y1 o% \' C( V1 M Q
for( int i = 0; i < graph->Get_pointsCount(); ++i){
% i! r$ J. E b. d if( -1 == dfs_id[ i]){, t' |8 Z4 b. `! k/ D# `$ `& D
dfs( i, -1);
& R8 X7 `# @7 }; n# L) Y }# M' y y( w; f0 M/ |
}
0 \# T9 D. e7 q3 ~7 G% B: D}
) e/ H9 ?2 u+ ]: U! t. C- `9 A( btemplate< class _Edge_Type> const Graph< _Edge_Type> * Tarjan_EBCC< _Edge_Type>::Build_tree() const{$ F8 J. D4 r6 N4 ~9 k' |
//< + Make sure @Func(Initialize) has been called
. q6 P5 o( y) X& k! P5 B//< + There is at most one undirected-edge between any two points in the Tree (i.e., @Ret)
$ a. h, D9 A- R' M Graph< _Edge_Type> * Tree = new Graph< _Edge_Type>( ebcc_count, graph->Get_edgesCountMaximum());. D% Y' ~2 Y6 x0 J
Tree->Initialize( ebcc_count);
! F f `" R" B+ R$ x' J for( int a, b, i = 0; i < graph->Get_pointsCount(); ++i){
3 x* @/ U6 ?2 B4 v8 \. ? for( int j, z = graph->Head[ i]; ~z; z = graph->Next[ z]){# r: Q! D' k! y) P
j = graph->Vertex[ z];" @& g! c: r9 ^( {: |) F
a = ebcc_id[ i];
5 P1 ]( y/ k5 M) E% ^ b = ebcc_id[ j];
7 D& n5 o) J4 j2 v0 `8 @( { if( a != b){6 z8 s! U1 b2 S7 @8 Q: v
// Now, there must has no edges between `ebcc_id[ i]` and `ebcc_id[ j]`/ [ o9 _2 l" k) R/ I& j- F
Tree->Add_edge( ebcc_id[ i], ebcc_id[ j], graph->Weight[ z]);
b. N9 E, L9 ~8 r, E0 ^9 } }9 A6 ~: B: C) ?5 t
}
. C0 z3 O& `; v }6 I l P+ U; O9 T
return Tree;
& s& Z$ [* R1 C p5 }8 Z* M8 V9 H}0 t+ w6 |) d2 E
template< class _Edge_Type> void Tarjan_EBCC< _Edge_Type>::dfs( int _cur, int _father_edgeId){( E$ ^' s" o3 M9 |+ u
stack_[ stack_top ++] = _cur;" R6 v9 }% D, K; Y: Y" A
low_id[ _cur] = dfs_id[ _cur] = dfs_idCounter ++;
& Y6 A: t6 b) P/ w+ ?& M! u; x6 t //--0 b" B/ P7 y% b3 Y/ D% U
for( int nex, edge = graph->Head[ _cur]; ~edge; edge = graph->Next[ edge]){0 F r. e1 p5 t K; e- `
nex = graph->Vertex[ edge];& i' _/ n1 P8 w- r) g
if( (edge ^ 1) == _father_edgeId){ continue;}6 n. x8 [% d) c' A
if( -1 == dfs_id[ nex]){& J& Z5 s' U. F5 B
dfs( nex, edge);
/ V" @5 @' A* w low_id[ _cur] = min( low_id[ nex], low_id[ _cur]);
# l, \" T" o1 {" F2 g }+ T$ I1 m2 `2 d
else{
& z/ t) a8 F) n5 B low_id[ _cur] = min( dfs_id[ nex], low_id[ _cur]);; z9 A: G* @* q
}
0 k8 J, d+ \7 D, B }& p; S8 W4 `# d# j5 A
if( low_id[ _cur] == dfs_id[ _cur]){
# x+ y4 u2 ^6 z, u; [ ebcc_size[ ebcc_count] = 0;4 _1 u/ c; ` [/ D- ?" Y$ k
while( true){, I) k' T* X. |- a3 d- }
int c = stack_[ stack_top - 1];" |0 f, Y8 e9 Y) b# u4 {
-- stack_top;
& x& W& ~7 Y, K ebcc_id[ c] = ebcc_count;
: m* y' |5 o. O ++ ebcc_size[ ebcc_count];
. {( a. X r; H2 Z9 M if( c == _cur){ break;}
) g$ O7 f" j2 D& f. F8 }/ w2 f }
3 M: v* ]6 }5 k Q ++ ebcc_count;
9 K1 Q* t, ]0 g4 s& l }
' ^: p. }9 M' m, h}4 K. h; ]; W+ x! g* u* X
//} Tarjan_EBCC-Implementation; Z* Y1 F4 l& g
$ U, M( w, T, ~: T, P) V/ o. PSCC有向图强联通分量* U8 `) d0 A* N# O9 n% b
//{ Tarjan_SCC# ~: y5 X! s5 X" J/ ~+ D5 m
template< class _Weight_Type>
" y7 V4 e% R4 Z3 lclass Tarjan_SCC{* ]3 }: ]* z. o$ d
public:
3 w' P9 C/ E. u! Y9 Q9 z/ r+ @- B const int * Scc_id;
: p. L/ w& l k const int * Scc_size;
/ V6 g: D {, J0 `$ }9 Q' k //-- variable ends* D: d, v( Z* l& _4 X# Z
Tarjan_SCC( const Graph< _Weight_Type> *);
7 q" t/ d E9 P% ]- C void Initialize();6 p; [- N( a) o
int Get_scc_count() const;
) x" Y" ?7 U2 j3 |2 s" K const Graph< _Weight_Type> * Build_DAG() const;8 H* O5 J% _/ v1 x* S9 e
const Graph< _Weight_Type> * Build_DAG_uniqueEdges() const;
. _6 y. a' A, s& iprivate:# \0 ^# g U' g4 B$ |3 K: m
const Graph< _Weight_Type> * ptrRef_graph;" k: U2 u: K6 r- {% j" ^4 U7 O3 V
int * ptrNew_queue;5 x. D% i3 w8 Z
int queue_tail;$ a8 j/ L/ I$ I+ [; l
bool * ptrNew_isInQueue;3 a! I" F6 {2 Q4 v1 b
int dfsOrderId_counter;$ \( C" u& ~' r5 o
int * ptrNew_sccId;! E1 l& U4 `) I( H' L* D$ ^
int scc_id_counter;' W" R$ K2 ^( X+ A
int * ptrNew_sccSize;
. G4 G, l; n* v% N A //-- variable ends9 s" a8 x+ O0 ~) H# r
void dfs( int);% y1 d3 F5 Y' H7 C1 Y8 C
};
4 d7 I, w% {+ ]0 o8 {. g0 \* l V# t//{ Variable-Annotation( {% ^5 |6 ~$ ]6 l) a0 j. R
// + @Var(Scc_id)" n! ]3 }. O2 X/ z. S) d
// . `y=Scc_id[x]` where `x` is a point of @Var(ptrRef_graph) and `y` belongs to `[0, @Func(Get_scc_count)-1]`
9 c+ t9 W9 [5 M0 u+ j" ~8 K, {// + @Var(Scc_size)
/ p6 \: O( [- L7 b/ O- 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)$ A2 `/ A- [8 v& y. _& N; e/ Q
//} Variable-Annotation: G, a4 E5 [/ U! V2 C( B
template< class _Weight_Type> Tarjan_SCC< _Weight_Type>::Tarjan_SCC( const Graph< _Weight_Type> * _graph)
& b$ p; D7 t9 t5 F7 f6 y3 ^6 o/ } :/ {1 X1 J4 A6 \# b
ptrRef_graph( _graph){
! k# ? X& ]( {9 I ptrNew_queue = new int[ ptrRef_graph->Get_pointsCountMaximum()];( P$ e/ R6 J- i( T* H
ptrNew_isInQueue = new bool[ ptrRef_graph->Get_pointsCountMaximum()];* H; X6 B* e! C3 _! _
ptrNew_sccId = new int[ ptrRef_graph->Get_pointsCountMaximum()];. o: k3 p" ~+ g p9 h5 I+ {9 L
ptrNew_sccSize = new int[ ptrRef_graph->Get_pointsCountMaximum()];
, H1 O9 T& q+ `/ b9 F, h I //--7 x- r- x# h: ?+ O; k& M0 t( U
Scc_id = ptrNew_sccId;* c; W- n! o6 k O2 S
Scc_size = ptrNew_sccSize;5 i9 G- n. t& Y( Q4 ]. D- e
}9 d$ a6 u M4 \# {+ M& I" K
template< class _Weight_Type> void Tarjan_SCC< _Weight_Type>::Initialize(){
$ u+ Y* D3 n# w. t5 `8 e- ]. z' T queue_tail = 0;
0 K( c$ l' M! s( m$ n0 ^5 I dfsOrderId_counter = 0;# F& u, d! Y% f0 t8 z
memset( ptrNew_sccId, -1, sizeof( int) * ptrRef_graph->Get_pointsCount());
2 |6 t" v% ?7 S( E6 _ scc_id_counter = 0;
& {* q& ]: R$ V$ A6 c3 ~* Y r for( int i = 0; i < ptrRef_graph->Get_pointsCount(); ++i){" i8 T& C/ M( r3 U
if( -1 == ptrNew_sccId[ i]){
4 V- h. o/ y" l* H# m dfs( i);. F) L; n- ?1 J+ T
}
, I. [1 d! _6 V2 v }
: L: z# F3 H8 m4 ]" Z) {}* F2 B& z/ F. g N: W
template< class _Weight_Type> const Graph< _Weight_Type> * Tarjan_SCC< _Weight_Type>::Build_DAG() const{7 W9 e4 d7 _6 H# `" v+ e" @
//< + Make sure @Func(Initialize) has been called. m* F! B2 A i. G
Graph< _Weight_Type> * DAG = new Graph< _Weight_Type>( scc_id_counter, ptrRef_graph->Get_edgesCountMaximum());; w: T @) i9 E$ d0 r
DAG->Initialize( scc_id_counter);1 `& R; K1 s- X4 I
for( int a, b, i = 0; i < ptrRef_graph->Get_pointsCount(); ++i){! w& b% {! [+ u9 T" j% _ I* f4 ]& z
for( int j, z = ptrRef_graph->Head[ i]; ~z; z = ptrRef_graph->Next[ z]){
- j( n) v. ~% a& W# H2 y+ x: u j = ptrRef_graph->Vertex[ z];0 |, G) z7 y8 j
a = ptrNew_sccId[ i];6 I; Y5 p$ J y) F8 U
b = ptrNew_sccId[ j];
' A% I! j. q% g7 u& g( Q if( a != b){. }! d+ t: A) s9 R
DAG->Add_edge( ptrNew_sccId[ i], ptrNew_sccId[ j], ptrRef_graph->Weight[ z]);- j+ f. _, p) r/ C. U5 o7 L
}3 J: [# _; \ ^2 l2 b8 e
}
% b) L; |& Z8 Y4 R0 C }) h8 k5 m3 a4 G" ^! c
return DAG;
0 |, |; ?2 O' s}
5 b5 K$ x' T" w! Q o+ K- F; Atemplate< class _Weight_Type> const Graph< _Weight_Type> * Tarjan_SCC< _Weight_Type>::Build_DAG_uniqueEdges() const{# o' W0 @, K' m- x
//< + Make sure @Func(Initialize) has been called, L5 I# F a( [. e* L: ^* I
//< + There is at most one edge between any two points in the DAG (i.e., @Ret)
5 f9 @ M; e: ? unordered_set< long long> hash_edges;6 S6 ?9 I" `- o1 E( b& [( e
Graph< _Weight_Type> * DAG = new Graph< _Weight_Type>( scc_id_counter, ptrRef_graph->Get_edgesCountMaximum());- n4 z5 G$ M& W( k. \
DAG->Initialize( scc_id_counter);
2 g" n! g! Y( H for( int a, b, i = 0; i < ptrRef_graph->Get_pointsCount(); ++i){$ N' p y9 p0 E+ B3 t
for( int j, z = ptrRef_graph->Head[ i]; ~z; z = ptrRef_graph->Next[ z]){
( a2 Z: z; A" p. h7 n j = ptrRef_graph->Vertex[ z];
; [; J2 B+ |, ]4 H& u0 s6 L: | a = ptrNew_sccId[ i];) {2 M1 V- ?) o9 h" k# X2 d
b = ptrNew_sccId[ j];
0 m3 B9 q+ `0 Q if( a != b){+ w, o% s% F7 d3 {9 \* d6 u
long long hash_val = (long long)a * scc_id_counter + b;; c* D8 Q; m' h3 V6 [
if( hash_edges.find( hash_val) != hash_edges.end()){
5 i. d( v! o6 f3 W& n$ H continue;
8 x% W8 H5 }4 T! D4 h0 j }
: B$ f$ S6 i% O9 b! } hash_edges.insert( hash_val);1 n* Z u% X6 ^4 c
DAG->Add_edge( ptrNew_sccId[ i], ptrNew_sccId[ j], ptrRef_graph->Weight[ z]);% \7 y6 i T9 d: J1 M l% X' z
}
, E9 Y6 o. y7 Z9 s; D }
. I2 X# ~' q: h/ I; \ }
' B7 M0 {! G f0 x5 z: z2 G return DAG;: R4 I7 K' g3 u9 y2 c$ `1 s
}
$ v) u5 N8 q/ s; c. h" b; xtemplate< class _Weight_Type> void Tarjan_SCC< _Weight_Type>::dfs( int _cur){
' t9 a( B, l$ c8 W6 S! k3 E ptrNew_queue[ queue_tail ++] = _cur;+ q5 H: F% t- z7 z; {$ x
ptrNew_isInQueue[ _cur] = true;
( {) V/ r4 X/ u$ s& [0 H" B int current_dfsOrderId = dfsOrderId_counter;
* Z J. K+ j+ t1 F+ E0 O ptrNew_sccId[ _cur] = dfsOrderId_counter ++;
1 J; t# j. [; [' w //--
# v7 @# g+ H5 q5 X: Y for( int nex, i = ptrRef_graph->Head[ _cur]; ~i; i = ptrRef_graph->Next[ i]){ w: s' B$ E9 `- Q
nex = ptrRef_graph->Vertex[ i];
+ o' i2 T0 t- {2 g) l+ W if( -1 == ptrNew_sccId[ nex]){
+ U0 ~9 c; V, x! l; x% E dfs( nex);
4 F" I. P" S; E }8 ?2 X9 O* P; Q, m: j, `
if( ptrNew_isInQueue[ nex]){
0 m6 u) d, }; V: F8 h" n& c. M1 { ptrNew_sccId[ _cur] = min( ptrNew_sccId[ nex], ptrNew_sccId[ _cur]);
B0 @" B: H! U2 B }, n& Q1 o8 X" |: t. K' T( F1 |
}( z$ P5 z% u+ k% o) @0 c6 S
if( ptrNew_sccId[ _cur] == current_dfsOrderId){/ _ a( i; ] Y' {$ |7 o% D
ptrNew_sccSize[ scc_id_counter] = 0;6 @+ ^/ M: [1 c9 O& I0 d2 k
while( true){% W' }9 k; t0 e" C: d' w8 F
int c = ptrNew_queue[ queue_tail - 1];: Y5 {& R# }% C) Z
ptrNew_isInQueue[ c] = false;5 V; u# g* u. ^3 Z+ Z* c0 o3 d: l
-- queue_tail;
- X2 s4 W/ ]: N. B+ ? ptrNew_sccId[ c] = scc_id_counter; e- _3 X# _* x! L" e7 ^: {
++ ptrNew_sccSize[ scc_id_counter];, E0 c: o- k$ t8 W, y( I+ Q
if( c == _cur){ break;}
5 f6 f, ]1 I% a) S2 S }# `7 e4 T, J* F5 G
++ scc_id_counter;/ x/ x2 o1 O% Q4 F5 n7 x. k
}
/ }! S/ a* k7 u/ V! [# s1 ]}& w6 }) y: T( A9 x9 v' F) Z
//} Tarjan_SCC
A* q$ {) I6 m1 x" o9 |( T% s. a; E" B& _ N. A( `$ g7 M `& a0 i1 G8 g
差分约束系统,不等式组& a9 ^, `1 H3 A9 u6 k9 A3 Z
//{ Minimize_InequalitiesSystem
6 |1 f( a. z0 W' Mtemplate < typename _Edge_Type, typename _Distance_Type>6 _# Z$ N8 N. [, ~
class Minimize_InequalitiesSystem{9 y9 m% }: a. n. A
public:
. R* |8 Z4 O" k- U! |' A0 R& M const _Distance_Type * Distance;
& o( W# f& ^$ W _ ^/ d //-- variable ends: \! g& ^6 G% a3 I! i1 \2 Z
Minimize_InequalitiesSystem( const Graph_Weighted< _Edge_Type> * _graph)
: \, W. @( j. d, N6 [% E) B: m :; K/ _# I; R/ M3 \7 u
ptrRef_graph( _graph){
- p8 x1 |* P" A. o( W+ [) x& c9 O; ? ptr_distance = new _Distance_Type[ ptrRef_graph->Get_pointsCountMaximum()];
$ p% M u6 r* T1 D! ]+ @! |6 i2 u Distance = ptr_distance;( c) z+ D& l( q( {
ptr_isInQueue = new bool[ ptrRef_graph->Get_pointsCountMaximum()];
) G! ^ r% Y* ]2 J- j ptr_queue = new int[ ptrRef_graph->Get_pointsCountMaximum() + 1];/ Z# z4 {4 f% ^' C1 v/ ]7 ~6 q
points_range = 0;9 r. Z. l/ s& |. A J
ptrNew_pathLength = new int[ ptrRef_graph->Get_pointsCountMaximum()];8 N3 z' b! H6 ?2 M
//--
4 a- r5 e5 r, i+ ?5 w1 f Initialize();3 r+ \# N8 h* \" e% {9 M" `
}
4 H* e: j7 L ^" n. N: b void Initialize(){
( R% R6 F8 O4 n/ P points_range = ptrRef_graph->Get_pointsCount();, x, g* H: V/ z
}
& Y: W+ L& ]7 {" f bool Work(){7 u7 l! }7 W6 i) l9 ^
memset( ptr_distance, 0, sizeof( _Distance_Type) * points_range);. v8 w5 t" K7 a. m: C. H# z' Y
memset( ptrNew_pathLength, 0, sizeof( int) * points_range);
1 J; c. ^* E ~' {/ U2 r# d! ` for( int i = 0; i < points_range; ++i){8 {! Z3 O6 L1 a7 m1 B
ptr_queue[ i] = i;
% j/ s9 {6 r9 N9 Y9 S }1 l. X% t9 L8 {- d% g
memset( ptr_isInQueue, true, sizeof( bool) * points_range);; c+ Z N& l: g5 Q1 D# y# u2 O9 p/ C
queue_head = 0;8 a% t' M1 Y0 B* Y- Y; ~+ n
queue_tail = points_range;# R9 M9 z- n" }- H
//-- }4 o& s8 `) D/ b z4 G
int cur, nex, edge;
( l* T( K$ J8 Z e2 F while( queue_head != queue_tail){* F8 y, H9 n( U1 ?+ j
cur = ptr_queue[ queue_head ++];
/ H- H+ ]+ t( o7 q" L' t, T* P6 R ptr_isInQueue[ cur] = false; Z1 r. k8 N3 a5 h( x
if( queue_head > points_range){ queue_head = 0;}
6 F; Z1 }6 C$ |5 `1 f3 ^ for( edge = ptrRef_graph->Head[ cur]; ~edge; edge = ptrRef_graph->Next[ edge]){2 _: f( u, o* z$ r3 i
nex = ptrRef_graph->Vertex[ edge];
7 D* F8 T! J1 y( v if( ptr_distance[ cur] + ptrRef_graph->Weight[ edge] > ptr_distance[ nex]){5 X) |& H# Z8 g( H: s# F
ptrNew_pathLength[ nex] = ptrNew_pathLength[ cur] + 1;
/ j7 u# p& r4 o1 k if( ptrNew_pathLength[ nex] >= points_range){8 L' i" ~' w& k& `, b) p
return false;' U$ ?$ M& E1 E1 a5 h9 y: G
}2 \, }4 I" j( T
ptr_distance[ nex] = ptr_distance[ cur] + ptrRef_graph->Weight[ edge];& q8 R0 J3 v0 h' d' e1 K& Y/ C' }
if( false == ptr_isInQueue[ nex]){- G) \" M8 I6 d2 K" \. w9 R4 p
ptr_isInQueue[ nex] = true;
! z( o: U n3 a) W$ ^ ptr_queue[ queue_tail ++] = nex;; k/ {+ \( r4 h! U4 V% L, E
if( queue_tail > points_range){ queue_tail = 0;}& n& R- v& \2 s, }
}
; f: t" y4 T0 m; E x0 U, X; S! N }
) `7 [/ W) c* O; X }, X0 ]( _* J- ]/ [3 j7 z# J
}6 I# z6 ?9 N& c+ G. L4 T9 x
return true;2 g0 i( C3 Q1 T' ~0 A: }# E
}, I$ u7 x+ m' @0 F8 K
private:
, Z: Z1 x& G u const Graph_Weighted< _Edge_Type> * ptrRef_graph;, {( B+ D) @# F0 T( R' F+ }3 C
int points_range;
4 X5 C! ?, s8 D3 e _Distance_Type * ptr_distance;
9 p) O5 k& Z7 I8 Y* ] P/ V bool * ptr_isInQueue;* P" n" z1 g, W2 P
int * ptr_queue;0 W5 s W& ?$ I* s% _) C6 e: s
int queue_head, queue_tail;/ {3 }8 `# V2 X# k/ _% C
int * ptrNew_pathLength;
( T3 E$ ~8 a( `}; ~+ Y& @4 T( {% B, ]2 {
//} Minimize_InequalitiesSystem
* [' s c1 K% V& l/ U7 E% g0 z- {3 H c' ?" r6 `" y
Caution5 A% q: C4 Z+ }0 P; Z3 `
9 x8 S. B) e4 q
`+` You should never modify the source-code of @Func( Work), otherwise, it means your algorithm must be erroneous.$ O1 {) z( j. x7 g( W/ _ A; [
1& O4 U) R. Y2 h) b0 b/ M
Annotation! i$ Z* E4 S; j L1 Q9 E! _
* u# P4 \5 ]$ ^+ W7 }
`+` @Func( Work)
# z% K8 ~; O) f6 R`1` `@Ret = true` means the Inequality-System is Consistent, otherwise it is Inconsistent (No-Solution)., l" Q3 K6 C# Z: b {6 D
`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`;0 V, l1 b3 }0 q1 A4 N6 }
`.` In other words, under the premise `all variables xi >= 0`, minimize every variable and also satisfies all relations (i.e., the graph)6 D6 ~3 y+ C& e
, B7 W: U1 R# y; J" `# S# L+ z0 r`+` @Var( ptrRef_graph)' B; G& n' H% 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.( \- Y; n& \3 W1 _2 a' y; G7 b
) g5 w3 Z4 H5 s$ y* }/ b8 |" s
数论
8 j/ e3 U/ o6 Z% S$ {矩阵乘法
* a. O. m% b1 a1 Q& C: p, f//{ MatrixMultiplication-Declaration) d# F% S8 p+ O- `9 H
template< class _Type, int _MaximumLength>
# e5 z- Q' z( W' E$ `class MatrixMultiplication{
5 ~. C( |3 p/ ^4 tpublic:
+ r: j! O& y: B; |. A6 v MatrixMultiplication( _Type);
; R5 ]! i/ o n9 r5 }! [ void Initialize( int, _Type (*)[ _MaximumLength], const _Type (*)[ _MaximumLength], const _Type (*)[ _MaximumLength][ _MaximumLength], long long);
3 |/ D! B- R. X- Sprivate:6 m+ f% U0 t& \! \( F
_Type modulus;% c6 ~+ H: S9 y* n* ~( W
int length;8 p s: q( U5 Z3 G: D( K
_Type factor[ _MaximumLength][ _MaximumLength];
' f8 [* ~1 M) o _Type answer[ _MaximumLength][ _MaximumLength];6 {1 ], W: @# O1 e7 T0 m
_Type temp[ _MaximumLength][ _MaximumLength];( A- A+ N/ e7 X2 x& R! j
//-- variable ends0 {+ P: t) j& F1 I
void matrix_multiplication( _Type (*)[ _MaximumLength][ _MaximumLength], const _Type (*)[ _MaximumLength][ _MaximumLength], const _Type (*)[ _MaximumLength][ _MaximumLength]);2 ~$ h' l8 O- n* g( h' g& f
};
* W- s+ `+ x8 W# k//} MatrixMultiplication-Declaration3 p _ Y0 Y4 }4 K3 q! N% G) a2 b* p
$ P6 k5 z/ A5 @+ C! Q//{ MatrixMultiplication-Implementation
7 p# S9 k: j0 r$ @! btemplate< class _Type, int _MaximumLength> MatrixMultiplication< _Type, _MaximumLength>::MatrixMultiplication( _Type _modulus)9 t" [2 N5 q8 t ^* \, d# k! P: e
: ?% y! N1 v! Q0 l8 o
modulus( _modulus){
6 I8 m3 W; f: Z1 i3 |4 j2 U( i}3 o _: Y h' S5 [9 R; ?/ F
template< 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){
4 x" d* m! s9 m3 ?% q5 v4 K//<
A* H( r, S/ W) u: x3 g; I7 H$ L// @Brief+ \+ e c% o3 v! G
// . `result = dp * (factor ^ k)`;: R. ?2 F6 Z0 p1 L7 E
// @Warning
, X ]/ d6 p( m; r// . Make sure the data of `dp` is `dp[0, ..., _length)`, the data of `_factor` is `[ (0,0) -> (_length-1, _length-1) ]`;
1 d/ l' C, A* i, l1 K! K Z ASSERT_( _k >= 0);
) L: X/ f! [" U9 [7 a/ [ ASSERT_( _length <= _MaximumLength);
: s7 ~9 V4 L) _% F$ c) m( l //----
4 m1 c( u& F" k$ E) F8 r3 t5 ` length = _length;
- h/ C1 [- P* C6 d. f3 F5 r) A+ I //--
( k- ^: L2 W4 W memset( answer, 0, sizeof( answer));
5 {- c1 {/ m- R* C/ i" I" Z/ m" Y for( int i = 0; i < length; ++i){0 N" X, N9 N8 T1 B" Q! t
answer[ 0][ i] = (* _dp)[ i] % modulus; if( answer[ 0][ i] < 0){ answer[ 0][ i] += modulus;}
' w4 S9 c1 [2 O9 P) j }
3 T4 K4 R. @2 Q" O: s" [1 _5 w7 _1 y for( int i = 0; i < length; ++i){+ D$ V3 L# Q" P7 N6 q0 W' d
for( int j = 0; j < length; ++j){+ N0 L" l# g4 s: L7 N, x3 J
factor[ i][ j] = (* _factor)[ i][ j] % modulus; if( factor[ i][ j] < 0){ factor[ i][ j] += modulus;}
; n4 F; j; v J \( y+ D }* E# r6 {; n. a* F, X
}
; I( b5 W9 p5 |: `* k: S //--
: I8 {6 U: N1 |3 j' O; Z2 ?3 W0 w6 g while( _k > 0){& ~, s6 O8 A* [# y% a1 E' ?
if( _k & 1){- p+ B, f u% l* i
matrix_multiplication( &answer, &answer, &factor);# g# U+ q7 n, ~4 h" z3 B! b0 j; X
}
$ L; k6 n$ _; j4 I& V _k >>= 1;
, _ o# {/ q3 M; L7 B0 h$ g# D0 d. C9 N matrix_multiplication( &factor, &factor, &factor);3 n) v; h% t/ q' @, |
}
. V# ]/ P) D6 Y //--
5 X U6 x0 N$ ?( x6 |2 o memcpy( _result, answer[ 0], sizeof( _Type) * length); // the address of `_result` equals to the address of its first-element;+ R/ h; X* X7 r7 b: T
}
6 V3 y( ?# A% M7 U: C" htemplate< class _Type, int _MaximumLength> void MatrixMultiplication< _Type, _MaximumLength>::matrix_multiplication( _Type ( * _result)[ _MaximumLength][ _MaximumLength], const _Type (* _a)[ _MaximumLength][ _MaximumLength], const _Type (* _b)[ _MaximumLength][ _MaximumLength]){
$ t1 C! a/ B9 y4 o" h( {& ^& K//<; X! I: p0 F G8 \ k3 [3 {" Q! p
// @Brief
& L6 S& L5 J' Z* p// . `result = a * b`;
: m$ A' L2 L- K for( int i = 0; i < length; ++i){$ R6 R% ~/ ^; e w
for( int j = 0; j < length; ++j){9 M/ w! P: a# Q+ r! A! k) H6 c5 h
//>> Cuz `result` maybe equals to `a/b`, you need store the result to `temp` not `result`;
- N; h5 M$ O, n* v& M" m temp[ i][ j] = 0;3 X- H8 e, V' w- Z# _
for( int z = 0; z < length; ++z){
! f! w4 G7 Q, R* d4 G- [ temp[ i][ j] += (long long)((* _a)[ i][ z]) * (* _b)[ z][ j] % modulus; if( temp[ i][ j] >= modulus){ temp[ i][ j] -= modulus;}
/ h2 G, t9 O# ]5 m }
$ i# p. s& M! N$ g2 l7 H }
0 x6 \5 H( Z& R! ?/ T: I2 ?2 z }2 v) a: D. v0 `( G
memcpy( _result, temp, sizeof( temp));
" h2 @ x2 n5 K' I' T}
) I% ]2 B$ }! E: H( z+ o* H//} MatrixMultiplication-Implementation( o6 D! o2 ^6 G2 [0 X% G4 H4 P7 w
* d& ?# Z z. g/ e0 W. s
@Delimiter
' E7 K0 e* r) J1 Z/ q! w. V* @' j8 R4 g1 ?5 G! y, `7 L# q, }% q
示例8 G0 X9 B/ z7 _/ M1 I
: N0 T. F$ T8 [( P
int Dp[ 4] = {1, 2, 2, 1};
; Q1 v8 ]$ w9 t( s4 v2 ~int A[ 4][ 4] = {{0,1,0,0}, {1,1,1,0}, {0,0,1,1}, {0,0,0,1}};
1 S% b4 ^" h$ I- R$ kMatrixMultiplication< int, 4> Mat( M);- V* q- p$ o1 w5 \4 A3 ]$ P4 x: H9 c
Mat.Initialize( 4, &Dp, &Dp, &A, N - 2);
6 \4 h' p' h* Y! t6 P/ j$ }! I7 J7 i! Y- o
long long ans = (long long)Dp[ 2] * N % M - Dp[ 3];1 |7 V* c; j- S4 [7 n& E
cout<< ans;' @8 Z6 i/ V) Q- |& c/ Z
1
6 w; a) |, E3 ^4 @5 [2
$ Y' o4 X$ P2 s% {" O, w' u3( c; P3 O( N `9 }, ~$ m1 X
4
8 f& P- W5 ~# b% b3 T2 L* ]5
7 t: g1 T7 d# m& i6 @# i3 j; x' h6+ x& ?( g ?0 Q( |" \4 t
7
% j6 Z+ q1 y# ~ ]/ p, c0 a/ w* c中国剩余定理
, t' t' K( a5 u# h0 {% Y. k% {朴素 CRT
" ]4 ] u; Y) e+ j//{ CRT-Declaration x4 ]6 X) j3 A3 w( i7 R+ A+ z5 J( P
template< class _Type> pair< long long, long long> CRT( int, const pair< _Type, _Type> *);$ X5 ]8 h- Q- x$ [ p1 B+ Y
//} CRT-Declaration/ H( Y2 K c3 _" Y
8 R2 @8 l2 I) G; }1 |! D- K% x7 c
//{ CRT-Implementation' r/ T* P+ I0 ]7 ~4 T) D2 s
template< class _Type> pair< long long, long long> CRT( int _n, const pair< _Type, _Type> * _arr){
8 n6 @' G! ]; N7 V$ f; h V0 P//<
% }% o) [: ?7 w c// @Brief
8 b0 B5 E D6 a// . Solve the system of `n` Congruence-Equations represented by `arr` (i.e., `? = arr[i].first (% arr[i].second)`);6 q6 i3 w' z6 G7 b
// . Once all `arr[?].second` are Pairwise-Coprime, this system must be Solvable (and Infinite-Solutions);! h! \- N3 m5 g; {+ _
// . @Define( `(a,m)` = @Return), `a` must in the range [0, m), and the Solutons are $a + kk * m, \forall kk \in \Z$;
5 O: y0 c" Q! V% O! k4 i// @Warning( k: U! v6 E7 t% f. P9 a
// . Make sure all `arr[?].second` must be Pairwise-Coprime;
! Y( @. C1 _3 g: z, N2 @/ y// . Make sure the Product of all `arr[?].second` in the range `long long`;+ \5 j- }! v2 @
// @TimeCost
8 H, L( w- y8 ^% y: X6 t) {4 K// . $n * 60$;4 z" K3 X( L- t. ?
long long M = 1;
# J' _* H9 |; S/ g2 F for( int i = 0; i < _n; ++i){& |2 B& X' X" O; k7 R1 |4 F
ASSERT_( _arr[ i].second >= 1);
. Z7 z; w$ T, s( ~" |0 } M *= _arr[ i].second;
, k6 G4 V+ Y7 [: J) W }5 y; Y n% d, @, d$ P5 @! W
long long answer = 0;
2 m' v( T+ j$ D( G3 I$ g, Q for( int i = 0; i < _n; ++i){6 Z2 T' \# Q2 F+ x
_Type a = _arr[ i].first % _arr[ i].second; if( a < 0){ a += _arr[ i].second;}
9 j' K) A7 z: h* j: v long long m = M / _arr[ i].second;
0 i! K& R! o# `+ u$ h5 P pair< bool, pair< _Type, _Type> > ret = LCE_BezoutE< long long>( m, 1, _arr[ i].second); // m * `ret.second` = 1 (% _arr[ i].second);
7 T% Y1 S1 \# H. k$ G ASSERT_( ret.first); // All `arr.second` are not Pairwise-Coprime which rebels the Premise-Of-This-Algorithm (See @Warning);6 a% L. |0 L( t& l8 z
answer = (answer + (long long)a * m % M * ret.second.first % M) % M;
9 w" n) h+ w( j0 u& R }
" `$ L; O% k* A( a# B( l1 ~8 S* r, g return {answer, M};0 _) {) l2 @" V/ I
}0 Z5 G& n+ Q O! M) `
//} CRT-Implementation- u1 w- H$ p/ T5 k% _# P
6 h' {0 D5 w( N( |( `拓展 CRT_EX; U3 Y) ], S; a$ V; R; j2 ?9 v
//{ CRT_EX-Declatation9 u' c3 a C2 P3 k' o
template< class _Type> pair< bool, pair< long long, long long> > CRT_EX( int, const pair< _Type, _Type> *);
; i# W1 s" t: J( `# A//} CRT_EX-Declatation
2 {' O) H1 E( r+ [3 k
2 Y+ x' |, G$ ~5 {2 J7 {//{ CRT_EX-Implementation
/ N& \3 x! V6 F- Stemplate< class _Type> pair< bool, pair< long long, long long> > CRT_EX( int _n, const pair< _Type, _Type> * _arr){& U4 a' T; O1 U
//<
5 q0 K7 r$ r! C// @Brief e! y! O9 y( \' \/ F8 U' j8 ~" M6 x
// . Solve the system of `n` Congruence-Equations represented by `arr` (i.e., `? = arr[i].first (% arr[i].second)`);
5 E' \: i. t2 |7 D// . @Define( `(r1, (r2,r3))` = @Return);7 M# k* |& q; g/ F& O+ `1 G
// 0( r1=false): There is No-Solution;' n4 v3 C% E& g& _4 m
// 1( ELSE): The Solutons are `r2 + kk * r3, $\forall kk \in \Z$`, and `r2` must in the range [0, r3);
* Y" l5 y$ ]) V// . All `arr[?].second` maybe not Pairwise-Coprime (which differs from `CRT`);
8 r% z% X$ L7 X5 s+ k// @Warning
0 Y0 n; P; R+ R! A8 R! j// . Make sure the LCM (Least-Common-Multiple) of all `arr[?].second` in the range `long long`;
+ A" R9 K: y- I// @TimeCost
0 F1 K! z2 U+ Y# l7 {7 J// . $n * 60$;
0 [) y# i9 X6 ~, _ pair< bool, pair< long long, long long> > answer;$ R8 X$ R3 a" C' W- X5 |
long long A, M;
7 H+ D; ? D1 L for( int i = 0; i < _n; ++i){0 J$ _3 v. @+ S& S' h* D
_Type a = _arr[ i].first;0 B! l' Z3 p0 a5 P" d
a %= _arr[ i].second; if( a < 0){ a += _arr[ i].second;}
0 s1 d7 z1 F3 d0 k //--" f6 m7 m1 D# @( T p8 k+ g
if( i == 0){! t& {2 I; j; N$ Z) K4 s
A = a, M = _arr[ i].second;
% ~1 _/ C, V! l continue;5 I. k- r% Y! B2 \7 {" M: i0 q* Q
}* n* l( K# ]3 i/ z
pair< bool, pair< _Type, _Type> > ret = LCE_BezoutE< long long>( M, a - A, _arr[ i].second);* K5 R/ t9 J: v' b; V7 o9 b
if( false == ret.first){2 @) R) ]; a6 T; e* G" ~
answer.first = false;" r [1 E8 P3 R m4 W. ]+ m1 E
return answer;
) l4 U" ?. N0 P }
# G/ z K' m; q# u4 m _Type gcd = _arr[ i].second / ret.second.second; if( gcd < 0){ gcd = -gcd;} // The GCD of `M` and `_arr[i].second`;7 Z8 i/ w' E5 Y3 S
long long new_M = M / gcd * _arr[ i].second; // LCM
7 S% E* |( V* \/ b( [8 Q: a5 Y A = (A + ret.second.first * M % new_M) % new_M;$ ?6 k( `. @% g, O
M = new_M;
% S2 i' \% t% b0 S- G }" N4 U+ G" E& a' g
answer.first = true; w1 y; c2 K/ K. e- Z' I1 N0 y" V# S
answer.second.first = A;
0 {. ?7 ~$ R. w0 N7 ~ answer.second.second = M;
1 ~' r2 a. d* G4 c: L% U return answer;
: k3 ] [+ x7 a0 @}
$ Y& e* J g$ e$ \; E//} CRT_EX-Implementation& {; b( C" r& i2 [6 h' ^9 J2 p
1
! P) q/ _- f. B# n6 r4 h裴蜀方程 BezoutE" ]: \8 c7 s9 C/ u
//{ BezoutE-Declaration# }- Z* J9 ^4 S& h+ K
template< class _Type> pair< bool, pair< pair< long long, _Type>, pair< long long, _Type> > > BezoutE( _Type _a, _Type _b, _Type _c);
[) m0 K9 y# ]//} BezoutE-Declaration
, t2 ] f) q* H6 \# e: s5 ^- C. F }4 D. h
//{ BezoutE-Implementation
# Q& U3 c+ Q' v4 t1 @template< class _Type> pair< _Type, pair< long long, long long> > BezoutE_extendedGCD( _Type _a, _Type _b){
3 Y- d3 x7 u$ z1 N3 p2 z6 b//<- V% o* g2 c1 n* L: l
// @Private
, _+ Z o" h# N, ^( j! M1 R4 T/ C// @Warning
/ N: h+ J, A+ `. w& x) _# P// . Make sure `a,b >= 0`, Not-Both-Be-`0`;$ F. F: Q& A( m5 V$ Z' ^: U2 p2 c9 S
if( _b == 0){
4 P `- g9 `9 {: W B/ Q return {_a, {1, 0}};+ ^9 z( t3 y4 Q5 M+ ?: y1 S* i
}7 P" U m' A- u/ p- s
auto pre = BezoutE_extendedGCD( _b, _a % _b);
0 Q# g5 d7 R9 X auto xp = pre.second.first;
) E0 J9 N- b9 ~ auto yp = pre.second.second;
9 `# g6 g* A0 ~% B1 S. t3 X+ d3 i return {pre.first, {yp, xp - yp * ( _a / _b)}};) k" v2 E G$ I3 i
};
& Y5 ^) V2 ~8 M: }template< class _Type> pair< bool, pair< pair< long long, _Type>, pair< long long, _Type> > > BezoutE( _Type _a, _Type _b, _Type _c){
: S9 s0 S U O8 S8 T. T1 h; G( C& k, D//<
: Z8 R; B, X7 T% V8 |( p8 q+ \// @Brief
F) E9 E2 _: J0 L4 {// . Solve the equation `xx * a + yy * b = c`, @Define( `(r1, ((a1,m1), (a2,m2)))` = @Return)`;
: d5 E( @6 U' T/ M( X// 0( r1=false): There is no Solution;
( P/ M" G: B; V, L) Z// 1( ELSE): The General-Solutions are `(a1 + k * m1, a2 - k * m2) $\forall k \in \Z$`;1 T, w" p" N" M! [: L
// @TimeCost
% L0 b% w, U7 O. f// . $\ln(a)$;
3 i2 @0 J; r: V! [7 m1 [( F// @Warning
* P* X9 z O9 }+ o; ~// . Make sure `a != 0`, `b != 0`;
" N( H4 Y3 {1 P) g ASSERT_( (_a != 0) && (_b != 0));
' p2 }- q- Q/ s; ?7 h pair< bool, pair< pair< long long, _Type>, pair< long long, _Type> > > answer;
8 R# ~' @; x. s1 I bool neg_a = false, neg_b = false;
3 A- g! t2 @* t- Q0 ?& P9 p if( _a < 0){ neg_a = true; _a = -_a;} // `x * a + y * b = c` -> `(-x) * (-a) + y * b = c`;: |8 I5 T; U- L9 |& E
if( _b < 0){ neg_b = true; _b = -_b;} // `x * a + y * b = c` -> `x * a + (-y) * (-b) = c`;
$ [$ G0 {% O- w# x4 B$ y$ a' D# J //--
" Q. F, a" {" Q2 W6 l2 } pair< _Type, pair< long long, long long> > ret = BezoutE_extendedGCD( _a, _b);6 |( W9 [& Y, ~5 y, L
if( _c % ret.first != 0){8 T1 @, ]2 S4 m7 n
answer.first = false;, Z1 `" Q$ u- o$ |
return answer;
# L! b* Y4 X. h3 d" O0 Q; A" K }
$ a8 s) l& O! {6 ^+ l( I' l0 k, g2 C answer.first = true;/ r% Z; X: B8 h. Q8 E/ p8 B0 y9 w
answer.second.first.first = ret.second.first * (_c / ret.first);
9 j1 [! Y- o P answer.second.first.second = _b / ret.first;# Q/ m/ l# ?! M3 z2 R
answer.second.second.first = ret.second.second * (_c / ret.first);
* ~0 |4 I3 Q6 f ` answer.second.second.second = _a / ret.first;
, E& b! x4 _5 [ if( neg_a){ answer.second.first.first = -answer.second.first.first;}; A2 M1 O- N9 t1 N
if( neg_b){ answer.second.second.first = -answer.second.second.first;}
7 S2 M0 ^ I7 i" V1 L- Z return answer;
( ?1 l* B# f u, Y7 G4 M}
- z* y( x" `: n1 y, m) g//} BezoutE-Implementation
; F9 g2 M9 s3 L: U. S$ m) l+ K2 q
线性同余方程 LCE: ]8 V) q' J1 t
裴蜀方程法 LCE_BezoutE
9 A0 P* a o" o& w4 J, K//{ LCE_BezoutE-Declaration
# H) u( l0 G: y# D0 {template< class _Type> pair< bool, pair< _Type, _Type> > LCE_BezoutE( _Type _a, _Type _b, _Type _mod);. z8 t. F0 Y- j. X8 `" B
//} LCE_BezoutE-Declaration
* x" i; d. ?& F6 h$ F3 A1 ]3 _8 e6 h$ o* w
//{ LCE_BezoutE-Implementation
& O# F$ F0 `) `$ |) P2 C7 ]template< class _Type> pair< bool, pair< _Type, _Type> > LCE_BezoutE( _Type _a, _Type _b, _Type _mod){
7 H: ?# O7 ~6 R! Y4 M. v//<& H6 G+ Y& d" T- A) S" U$ A! R* O, g
// @Brief+ t( J" T* K5 i, a; b8 u
// . Solve the Congruen-Equation `a * ? = b (% mod)` where `?` is @Return; @Define( `(r1, (a1,m1))` = @Return);) |7 m2 ~) ~7 L3 O& x! Z- K' I) [
// 0( r1=false): There is No-Solution;
2 ^) o% I, Z, Z. V7 ?// 1( ELSE): The General-Solutions are `a1 + k * m1, $\forall k \in \Z$`, and `a1` always in the range [0, m);: T$ z8 c1 q9 {6 D$ p1 A( u$ x5 l
// @TimeCost
5 S0 c# `9 u" I( J6 }1 j// . $\ln(_a)$; f9 ] _& n3 Q
ASSERT_( _mod >= 1);' m# a* p0 p$ _( V1 T+ ^
pair< bool, pair< _Type, _Type> > answer;4 _9 n! p/ |1 i- d9 ] N
_a %= _mod; if( _a < 0){ _a += _mod;}
4 j+ G) ~6 V) _; | _b %= _mod; if( _b < 0){ _b += _mod;}+ ]3 N8 Z. [1 \' b0 [
if( _a == 0){0 o+ y, ]9 {# k+ Q& P6 O) y* |
if( _b == 0){
. M( c Z3 q3 ` answer.first = true;
* c* X0 u' P4 [7 t% w% D5 y+ X z answer.second.first = 0;5 W/ V2 g( J5 X; P- n
answer.second.second = 1;
$ e x( m( N- o/ n0 G' R return answer;
8 _3 x& `9 }/ ]% T/ X6 a/ Q }- h& A: J: H7 M+ m! ^1 m
else{
: Z1 k' D4 R: S answer.first = false;
' H( j1 M5 k+ d0 A7 o/ s8 R4 P return answer;
. B# d0 C" H$ R# w }
5 q0 h0 f: T% \3 I* @* D& e }0 l! J: m, E4 B- {
_Type gcd = GCD< _Type>( _a, _mod);
8 `; A3 K6 M# F8 b2 ]6 L" X) i pair< bool, pair< pair< long long, _Type>, pair< long long, _Type> > > ret = BezoutE< _Type>( _a, _mod, gcd);
! M! J, Q$ m; ]3 n ASSERT_( ret.first);
$ i' o, S& T' X8 k2 N0 c5 D! S# r+ W L& U if( _b % gcd != 0){& j: J4 A/ }- ]) |
answer.first = false;
0 H9 R# Y4 _; P, s7 { return answer;
* @% R! W# ^, E. M& _ I }! Z; g, a' P- r: t
answer.second.second = _mod / gcd;
9 s2 y! ^6 q3 T; {7 ^& o! w answer.second.first = Binary_Multiplication< _Type>( ret.second.first.first, _b / gcd, answer.second.second);( @- Q- Q g- R
answer.first = true;
7 q( r: P) s* v$ f/ L) b# O7 B return answer;
3 D; }# V) M3 t, D! f& f}
$ b. n7 {/ a; _//} LCE_BezoutE-Implementation
* v: a* N6 j3 @5 f+ D, Z& H' F' e6 s
高斯消元线性方程组
0 ~5 [! O. [# Y1 f2 O* j" X3 X0 m//{ Gaussian elimination+ S9 E3 S/ {* s2 h4 v7 W& d
double Aug[ 105][ 105]; //< @Abbr( augmented matrix): D4 T a& ^/ w j
int Gaussian_elimination( int _m, int _n){
' I9 _2 v6 c4 w; i, s0 N5 g//< @Par( _m): the number of equations5 @8 e! u* u; |
//< @Par( _n): the number of variables6 l; f. P$ S( X$ d. t
//< @Return: (0 is unique solution), (1 is infinitely many), (-1 is no solution)
5 v" w* G' X* d; s# p7 P int rank = 0;2 f) _7 T' ?! {# N' H; r) v
for( int col = 0; ( col < _n) && ( rank < _m); ++col){
* |# N7 q! c0 l7 n* T int max_row = rank;
9 X7 h8 s8 f! ~2 n for( int row = rank + 1; row < _m; ++row){
% n- g1 ?+ x$ M6 g if( fabs( Aug[ row][ col]) > fabs( Aug[ max_row][ col])){1 K3 r# E, c9 I1 d/ T
max_row = row;
$ Z f0 e- }8 x4 y/ E5 _$ l }
/ l5 n# i; H* L+ X# B }
" U( G0 h1 f: Y if( 0 == Db_cmp( fabs( Aug[ max_row][ col]), 0, Epsilon)){
+ N, [8 L, d! P //* either no solution, or infinitely many.
8 `$ f) h7 _* V! m& Z! ?0 d continue;
% s/ I& f# t W }
6 O& [ `# j# x1 R' O, K //{ swap two rows& w; k! h* N" R
for( int c = 0; c < _n + 1; ++c){
0 ^! l% c3 k- M$ R; n. W. G- \+ \ swap( Aug[ max_row][ c], Aug[ rank][ c]);+ z1 c8 u+ u+ x5 [' ^
}
7 Q9 }" H! _# w" k //}
s7 |3 h- {3 K C# j$ Z //{ make current pivot to `1`( c3 f& N9 f' h/ j; `
for( int c = _n; c > col; --c){% H/ v) a# {: C3 [5 U, o! H
Aug[ rank][ c] /= Aug[ rank][ col];
g8 D8 ]" q. [9 R& C5 o" Y& t }
) z3 p, g; e7 {* a& a; f* t Aug[ rank][ col] = 1;# F# m+ c' `7 {( y2 j
//}2 T3 X) U$ D& p& u) X# P' W
//{ make all rows below current pivot in the same column to `0`+ y0 t5 ~2 r3 N" J b
for( int r = rank + 1; r < _m; ++r){* \" G+ |2 b; I1 L
if( 0 == Db_cmp( fabs( Aug[ r][ col]), 0, Epsilon)){" g$ N7 d x+ l! H
continue;& L8 W4 p: @/ D! G6 ^
}
9 Z, {$ r: k8 b2 w for( int c = _n; c > col; --c){
$ e, p* [) t) p& D% \6 a Aug[ r][ c] -= Aug[ r][ col] * Aug[ rank][ c];
& o& c# F3 P; O2 J }* `5 w* p* o: C4 U; V
Aug[ r][ col] = 0;3 {+ j! @, q( a M
}
% D6 K7 U C/ y/ ?( B; V ++ rank;% I. c$ H9 i" J$ S) G; {8 ]5 w+ ]
}% ]( d7 h! J9 N3 k) H, r1 o" u
//--) ?- L* n! S+ z. z1 h$ l
for( int r = rank; r < _m; ++r){7 {+ n; M# W6 D8 e
if( 0 != Db_cmp( Aug[ r][ _n], 0, Epsilon)){
; c) t! @5 p, ` return -1;# |) Z# C& j) f
}1 [3 \ J" l9 B# q
}/ V N2 c" m6 D- e& s
if( rank != n){
/ t, `7 }* i, V* V# v return 1;; W1 r8 t7 k& ?5 }/ ^, N
}' q1 }4 o2 A7 Y
//> the upper-left `_n * _n` submatrix of `Aug` is a identity-matrix/ ~) h7 T, o& W1 |; f9 k: k' @6 p2 h+ }7 Z
for( int r = rank - 1; r > 0; --r){
* B& ^& |' i8 y/ m O% [5 D$ l$ l for( int rr = 0; rr < r; ++rr){
! I7 D/ d- p3 o( n- ~3 T* l5 N2 E3 O if( 0 == Db_cmp( Aug[ rr][ r], 0, Epsilon)){* h; @& w9 |8 x. e+ g
continue;: a0 r' r9 ~- l- W
}
5 p3 A; Q+ d2 ~: d9 [! M& X7 r0 v9 H Aug[ rr][ _n] -= Aug[ rr][ r] * Aug[ r][ _n];# t5 I: d6 d8 x2 Y2 Y
Aug[ rr][ r] = 0;
/ D: N, S5 Y5 U; V! A/ T! n }* ]" a+ `* ~. j2 [' Y
}
5 x# q, J9 `5 p& B return 0;+ r- ~, }1 a m' ]1 Y- D/ r: S# O! V
}
2 v) B: f" ?7 m$ P//} Gaussian elimination' S. x2 T4 R8 r- Q
9 b: u6 e5 C4 r/ P) a
, E* K4 n/ u" u, v% h, f |
|