|
|
算法 {算法代码模板,算法模板编写规范}5 t$ o9 O8 ?2 G$ P6 {/ u+ ^, R
supimoTemplate.cpp5 q8 R# V' o+ w- m
代码
9 w+ U2 c0 H- J; U8 K#define ___SUPIMOenvir_' e$ _8 v8 T! S6 ?8 }
* a) a. P* L c2 H$ w( x6 [#include <bits/stdc++.h>1 Y$ K/ z7 ?6 g- H, {
using namespace ::std;/ @( w4 X- z: N8 h" x
0 I+ y! E$ N) q% Q0 Q#ifdef ___SUPIMOenvir_
5 y8 F3 o8 e0 k& q4 N* { i #include "supimoDebug.hpp") h% V0 e3 ]$ U) K
#else
% _9 Y% }6 N' W: G #define TOstringITEMS_( ...) ""
! f' J4 l* F! q { #define DE_( ...)- A1 p$ ?2 A* `( r7 q3 z
#define ASSERTcustom_( _op, ...) assert(_op)# S2 y. J8 x* d- q
#define ASSERTsystem_( _op, ...) assert(_op)8 u0 J2 k0 [, F2 j- e8 E! R% @
#endif
* ]* W; d, q k( |* O
1 S1 F0 _( q+ [#define ASSERTregion_( ...) __VA_ARGS__
% T' n' E$ {( `" G1 \+ e#define ASSERTsentence_( ...)
$ q+ y2 {& _7 F, G5 m#define EXIT_ std::cerr<< "\nExit(2267): Line("<< __LINE__<< ")\n"; std::exit(2267);
8 R# g% T1 R: ]. W, B. G) k#define EXITcounter_( _max) { static int cont = 0; ++ cont; if( cont == _max){ string str = "Exit_Counter(" + std::to_string(_max) + ")"; DE_(str); EXIT_;}}
8 E/ R# Q5 V( ^3 X: q; U2 ~7 c6 t#define FOR_( _i, _l, _r) for( int _i=int(_l); _i<=int(_r); ++_i)
" f$ h3 K. r$ \1 p b o9 B9 }#define FORrev_( _i, _l, _r) for( int _i=int(_l); _i>=int(_r); --_i)
( V# ^) u5 U6 C' X3 m- m5 S1 U f9 q1 g' v: @8 `
using Int64_ = long long;
6 J8 w. k# m0 L. d, \/ U' C7 T- }$ J4 d1 d1 x+ r/ K
. R7 y; _+ t L4 {+ u
void ___Solve_oneTest(){- H: w* b" c0 u# w( I9 k, a! r! `
}% Q' @, u T3 _+ c3 r9 p7 ^
void ___GlobalInitialze(){
\6 `% m# f1 n0 H3 }% }2 u# ~" y7 V( v}! \+ K5 y" U8 ]5 H+ G5 ~( L! O
int main(){/ Y! K( i' q& @5 g
std::ios::sync_with_stdio(0); std::cin.tie(0);
* e I/ y9 O; P4 n3 O5 b/ |. l std::cerr.setf( std::ios::fixed); std::cerr.precision( 9);
% ^0 I7 l) z% u5 c0 D6 [+ Z std::cout.setf( std::ios::fixed); std::cout.precision( 9);
7 [2 N9 N# `3 a" R6 r0 [. b4 ?9 A) j( K$ R
auto ___Solve = [](){ // Problem-Input' L4 i7 I& s# c. r3 I* t
constexpr char MODEisSINGLE = 1;+ G7 p, g% v9 m6 \6 o: t6 _3 ]
int testsCount;$ g {6 E: p E% v! `" v8 V$ T
if( MODEisSINGLE){ testsCount = 1;} else{ cin>> testsCount;}
- d- o' {* ?1 O( E8 F( U, _4 \ for( int id = 0; id < testsCount; ++id){
: `. u2 n1 s& L! T4 g, p if( id == 0){ ___GlobalInitialze();}, _- k0 i, @8 P
___Solve_oneTest();5 ~& {2 x* A2 h5 f$ {5 g' l
}1 p2 a+ [5 x6 _
};
# Y9 F4 q7 N# f6 R#ifdef ___SUPIMOenvir_
1 Q; [9 e2 B. P' C$ K" o9 m while( 1){* D" S5 b# {/ Q- _
std::string flag; std::cin>> flag; ASSERTsystem_( flag.substr( 0, 10) == "#___Input[", flag);
( v1 h: F3 B+ E! I! [6 s- Q flag.replace( 4, 2, "Out");
/ ]& e/ e6 |8 |7 [+ j0 E7 {' Y+ F std::cout<< " "<< flag<< "\n"; std::cerr<< " "<< flag<< "\n";9 X& x& V7 S- x7 J# ~
if( flag == "#___Output[-1]#"){ break;}9 G* Q- k s% W7 M
// int timeStart = std::clock();
, O4 k' N& \% ~6 x6 d& _ ___Solve();. l, h) I! s1 V
std::cout<< "\n"; std::cerr<< "\n";9 w' B4 N8 d( _ g& R1 I/ Z( M
// std::cout<< "TimeElapsed: "<< std::clock() - timeStart<< "\n";* h/ ~8 _5 ~- D8 A9 a" ?* h9 n
}
9 _1 q6 f: m; ~& X#else
9 P. F2 F& Y$ A1 W l9 w1 _ ___Solve();
' [9 [% l8 }, |9 b/ M#endif
5 n3 G5 F9 r4 l: l" E3 _( H; M
' l! H6 [! M# V6 z return 0; N# T/ `9 ~( L
}
4 @9 W1 v1 i4 f) J- d5 r+ l$ R1
! c ?- {- K3 k2# ~# v4 m0 R9 [/ ?$ ]6 d+ U4 e
3
, `# ?$ h; [7 T' i3 ?$ B3 s/ N( k4
+ ^: w" `) K( y, Q7 F' \5' p# W) o- o/ B3 \ t0 Y# H
6- {9 o' j) I2 U( A$ P
76 I" u4 r9 M. V: y8 i* v
86 v7 Y x( M e' z6 Y
93 I7 L' k$ z+ ^/ z ^
10
6 d i$ m8 m1 Z- ^9 [* J11$ X1 d' |# r f" }
12) s! M' F5 x( q+ V$ X5 ^
13) P+ a6 b) ?' ^' E1 G3 n2 q
14
$ A. M- p) {6 B, U15
' [* c, G. ~# c5 s16
0 l1 ^1 I$ b5 o( O$ [3 p+ i; I17
: z5 A$ B5 U/ u/ H5 }+ l188 p- A. ~! c4 `" {
19
3 b6 y; Y0 x! X" M20
8 q- T: K- @, y& ]" }( |1 |+ n212 l- r# R; L# v. j. `/ X
22
' q% F* M( w; G4 p23
/ [* ?! _, h( O7 {24
+ m6 @2 Y8 ^( N6 F; I25* \; _8 f1 G2 q8 |
26! k- Z* t0 L$ x7 H/ l- W; m
27
) G7 ^6 n$ e& ?- j28
; q e, A, r2 @29
b; h) V0 V( O4 K L2 l30
9 ?' z7 u0 [! H O0 r8 M1 `31$ ~: `; C3 k9 P4 G% o
328 }( w" z R$ ^3 ?! |
33
9 Z/ E8 F+ S9 s w D) u34( W9 S6 l3 v; a0 R; E$ u
35
4 Q1 F9 o' [% x( S1 B( o36* h& u& W: R2 i* C1 m* g6 [
37
* q$ W+ @$ o) |38
# O" M/ t$ F& O X: a397 @. K# S$ N0 Y8 M
40
6 G- V9 X7 @+ o( O$ a410 f2 n& F: Y, i; V" G
42
1 A) |* S" D# m$ r4 h% B/ H43
* i& }7 z/ Y% P. S. a444 p6 a+ O* B3 p* v5 Q
459 g4 {: [6 D8 |* a4 D! T, ?
46
. |2 D. Q `1 j/ X! ?$ o; x. p476 Z% i* ~$ z" X$ O7 {
48
# F; t' x. F" R3 @; [49) }' K; f+ |9 c7 h- a! _
503 r1 y3 M' V _- W1 E9 d6 o
519 L M2 @9 u( ^' d
527 G0 p* Z" @' S% ]2 G5 o" g( @" e
53
' k- \ x. @' i4 S! {: h+ d8 ?! ?54
8 |+ S/ C ]8 T0 ]; l2 v! Z/ B55' I0 a, C+ K& j5 ~ G
56- O T0 j- @8 ^& Z" p2 V
57
% n, M) Z. {8 J58% e9 F$ L# o7 W2 o' e1 o8 A
59 g2 b. e/ B6 H! I
supimoDebug.hpp
8 }5 q3 n4 p, z5 v0 O g: ^代码8 H; W4 d5 h& x2 d9 U* T9 s
#include <bits/stdc++.h>
. C6 u% `9 N. P" N$ d( P5 b
- A6 R- ^ S8 R+ `2 ?8 I8 b#define VARSandLOCATION_( ...) std::string(std::string("{File: ")+ __FILE__+ ", Line: "+ std::to_string(__LINE__)+ ", VarName: ["+ #__VA_ARGS__+ "]}"): J/ F, D9 G* F) b" d+ [" {
#define TOstringITEMS_( ...) ___DEBUG_::ToString_Items( __VA_ARGS__)
% _# s) R7 Y% L% |# i#define DE_( ...) std::cerr<< TOstringITEMS_( __VA_ARGS__)<< " "<< VARSandLOCATION_(__VA__ARGS__)<< "\n") k5 g% H" {' n2 F8 z4 E% f
#define ASSERTcustom_( _op, ...) if( !bool(_op)){ std::cerr<<"Assertion_Failed(Custom): ["<< #_op<< "] {Hint: ["<< TOstringITEMS_( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< "); Line: "<< __LINE__<< "}"; std::exit(2267);}. h# S% q( i7 d# S A- E& ^: R
#define ASSERTsystem_( _op, ...) if( !bool(_op)){ std::cerr<<"Assertion_Failed(System): ["<< #_op<< "] {Hint: ["<< TOstringITEMS_( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< "); Line: "<< __LINE__<< "}"; std::exit(2267);}. h( c( j, M0 {8 n
" s5 s, ~) I4 F5 o- k u1 vnamespace ___DEBUG_ {
6 T. m: w8 J4 u& U1 a( n5 f //>> 所谓`Container`是指 可以通过`for( auto i : S)`来进行遍历的;! ], |/ l" d! o
template< class _t> struct __IsContainer_Unwrap : std::false_type{};" g1 j9 \3 y7 N
template< class _t> struct __IsContainer_Unwrap<std::vector<_t> > : std::true_type{};4 s M3 W/ E& E1 f/ K
template< class _t> struct __IsContainer_Unwrap<std::set<_t> > : std::true_type{};
& R9 Z: z( g0 i3 R- ~ template< class _t> struct __IsContainer_Unwrap<std::unordered_set<_t> > : std::true_type{};
9 E' T; d5 d a2 S R template< class _t> struct __IsContainer_Unwrap<std::multiset<_t> > : std::true_type{};
, _7 a8 ` g- W/ v$ y6 |; c! E. W2 ~ template< class _t> struct __IsContainer_Unwrap<std::unordered_multiset<_t> > : std::true_type{};* b: b/ }% s7 b! x
template< class _t0, class _t1> struct __IsContainer_Unwrap<std::map<_t0,_t1> > : std::true_type{};
8 X# C# H7 X1 b" n) P5 o" h0 S( J) \ template< class _t0, class _t1> struct __IsContainer_Unwrap<std::unordered_map<_t0,_t1> > : std::true_type{};
5 @ A; M( H0 F7 w Q template< class _t0, int _t1> struct __IsContainer_Unwrap< _t0[_t1] > : std::true_type{};
3 i) h6 x& B6 ^% s( r template< int _t1> struct __IsContainer_Unwrap< char[_t1] > : std::false_type{}; // 特判, 字符串常量"..."不属于容器;
6 u* W" Q3 c* `6 y7 g% k3 n- \ template< class _t> struct IsContainer : __IsContainer_Unwrap<std::remove_const_t<std::remove_reference_t<_t> > >{}; // 不能用`decay` 否则`T[N]`就退化为`T*`了;! _; r( n0 z' f$ Z
4 I* P y' r$ G2 r7 k template< class _t> struct __IsPair_Unwrap : std::false_type{};
. j- [* f3 k4 P/ p- Z. j2 ] template< class _t0, class _t1> struct __IsPair_Unwrap< std::pair<_t0,_t1> > : std::true_type{};( E+ A, {3 {1 `% d3 W- i$ `/ K* l
template< class _T> struct IsPair : __IsPair_Unwrap< std::decay_t<_T> >{};" l9 e7 m% d) {# h" ~
+ \5 J; o2 Q. l2 N0 M8 c template< class _t> struct __IsStack_Unwrap : std::false_type{};, \ h# ?1 [; J, C" ]( S( l
template< class _t> struct __IsStack_Unwrap< std::stack<_t> > : std::true_type{};
6 Q1 B* ~# q2 X template< class _T> struct IsStack : __IsStack_Unwrap< std::decay_t<_T> >{};
# S7 F) v; I" I2 S* `9 z$ R2 E, S5 h6 H( {
template< class _t> struct __IsQueue_Unwrap : std::false_type{};& D X( J$ s8 y r) ^
template< class _t> struct __IsQueue_Unwrap< std::queue<_t> > : std::true_type{};* W$ b, h7 \' T+ S5 _; f% o
template< class _T> struct IsQueue : __IsQueue_Unwrap< std::decay_t<_T> >{};
6 Q/ }2 n% |8 g
! T5 _; p2 f0 ~1 H+ N+ w template< class _t> struct __IsDeque_Unwrap : std::false_type{};6 g' u1 P* E F0 T0 ]2 l
template< class _t> struct __IsDeque_Unwrap< std::deque<_t> > : std::true_type{};
, Q1 C7 I$ P8 E, h template< class _T> struct IsDeque : __IsDeque_Unwrap< std::decay_t<_T> >{};
+ d$ Q. D# o9 H1 @$ h- H0 C/ M' x7 A9 E; {" X
template< class _T> std::string ToString( _T const&);5 k, ?" x- e# R5 i1 J5 e6 ]
7 O$ I v- S6 F5 I) U; `% I" g template< class _T, int _Check> struct __ToString_Category;7 }* E3 S! Q$ ]! E+ j
template< class _T> struct __ToString_Category<_T, 0>{ // Single% T- l @/ T, q! V5 `; t
template< class _t> static std::string TOstring( _t const& _v){; s9 W; Z+ P8 u. ~
std::ostringstream ANS; ANS.precision( std::cout.precision()); ANS.setf(std::cout.flags()); ANS<<_v;
4 K, C$ Y) ^" ?6 S+ s return ANS.str();! x$ l* l* y1 g% g2 o9 T6 A
}
% K" v7 S# g P! r. u 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;}
# j f! S. U+ p3 _# f" N/ r6 C0 q% u 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;}/ R# H6 }) I; C/ j
static std::string TOstring( bool const& _b){ return (_b?"1":"0");}
( r9 v3 f8 I7 C* F( } C0 ~, R static std::string TOstring( char const& _a){
% \0 f) D t% @$ I* _8 k/ ~ Y" y if(_a==0){ return "'\\0'";} // 否则因为她是*结束控制符* 会导致`ostream<<char(0)<<A;`后面的`A`不输出了;
8 G m* m' E1 p+ S" J std::string ANS="'?'"; ANS[1]=_a; return ANS;
# V/ `) b, O- X. y5 o3 o% e }. S) ~6 p3 E0 D$ D, k( R
static std::string TOstring( char const* const& _s){ return std::string(_s);}
8 {' @' q8 \. V# }: n static std::string TOstring( std::string const& _tt){ std::string ANS="\""; ANS+=_tt; ANS+='\"'; return ANS;}
4 `9 e3 O# @+ E };
: b- c- a( G- o& |- A; A template< class _T> struct __ToString_Category<_T, 1>{ // Container
7 h5 _7 D5 E& B9 L template< class _t> static std::string TOstring( _t const& _v){
8 t2 ~. w7 U9 Q std::string ANS="["; bool first=1;! a: z, K" L6 x% k& D a7 j
for( auto const& i : _v){ if( 0==first) ANS+=","; if( first) first=0; ANS+=ToString(i);}
+ e2 r6 N) m% h" g% q ANS+="]";
/ U4 {0 \0 U9 a5 C7 U return ANS;: d, s1 }1 q4 }9 W2 M6 k" {
}
* @: n0 |6 X' d };
+ m0 ?" [4 ^7 V; `- O0 E template< class _T> struct __ToString_Category<_T, 2>{ // Pair
! k- d5 v2 z& }) Q; k 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 H1 S0 o- J7 Z };5 x6 t. J3 E- }- \# ]8 w7 L
template< class _T> struct __ToString_Category<_T, 3>{ // Stack
; h4 m& I0 I+ J* {; \ 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;}* Z! D' |4 Z" A: x( i0 l4 g5 y
};4 S! Y9 |% R5 J$ h( x1 L) D& {; M
template< class _T> struct __ToString_Category<_T, 4>{ // Queue
7 A. h7 B( M+ r, i- e( W 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 `! _) d$ Z5 c/ |: e
};
\' \6 x* _( x' E- J% o( P template< class _T> struct __ToString_Category<_T, 5>{ // Deque" w, e+ x- _7 u
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;}
8 J& `, t L3 E; Y2 Y# @; J$ W };& f" L) [: H* Z& b
: j, \6 p2 }: I) T6 w5 f" j 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)))))>{};
/ \; x; J% P% A3 ?# Y; V: x) u* P! A, T' f; X
template< class _t> std::string ToString( _t const& _v){ return __ToString<_t>::TOstring(_v);}
% ]$ _9 f' H7 A& e3 N: q
- L* }/ p1 e1 g0 L& f: n template< class... _H_> std::string ToString_Items( _H_ const&...){ return "";}
5 u) N; n' r3 ?+ q' t template< class _H_> std::string ToString_Items( _H_ const& _h){ return ToString(_h);}
' F0 a, x9 y! n3 q# R 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;}: K! ?: `+ x* ]* h- c
}( C) j7 U, {) P2 S, Y- [# y# R
0 g5 R. ^2 r; I' B/ p. w( s q, m1% r7 }0 a* C1 i. ~! @
2
. _# y. {- D+ I& s4 O2 u q32 \/ L' R, n8 F! k6 u# W0 o
4% |4 J+ W" ?: }: J0 C9 `# ?4 g' g
5
9 `4 ^/ T4 @. c/ Y: |! u67 f% W5 S4 x4 \) |: @5 B5 i0 f
7( j S) f8 B' t0 J- R! |9 R8 h
8
& M( S$ A# T; d* b# C* X& X0 R92 b- \8 m s& C4 ]8 Q& \
10+ v4 P! ^% V+ \* q
11
2 o3 U( E- }; v; D% T. @, I12
+ u$ M/ L& \5 A+ A4 j% D( D# L& y, Z# L2 W13
( _! P% S: G( \14. E. I: C, [. K( @/ H
15) H: ^, r" K* [5 `9 _
16! g) z! K; P7 }8 Y0 p J
17
3 c k+ d0 m9 `18
% E7 l" k0 H8 D# B1 j: m: X19
/ Z, j) d0 u- d, g$ `20
" j0 ?9 J& G. J5 L t21* p" S ~3 M- X8 |0 w7 k
22
! _" V f S1 ^/ m$ L9 T23
- z4 ^8 Y1 P6 F! @2 F2 \, u, s; J7 }24
: z m& q6 R$ l8 i25
7 i% l% b3 A0 [4 Z" k& J266 E2 Q# Y0 z( I9 \. u# S2 @
27
4 j; _! \* u2 o6 h/ S7 r x1 z4 ^28
) t; s( f/ R1 E9 v0 A; o( b6 a! J: [29
6 f, l' q) {: U1 z- I30 l T; u7 [- v1 E
31
8 Y; s e: w- u$ |% z2 D32 t4 p# F- z# ~2 T- ?
33& F5 f, }' b( N% s5 K, z5 D! i2 |
346 z+ f: @4 i2 `4 V6 _$ S1 ~
35
2 t: Y! h0 o( ]3 N! u2 f0 [3 x7 Z36& N! M$ W7 w* D8 s* B( S$ f
37
9 k6 w. d) v5 D5 \38
- f( r( g7 N/ M. f, o0 N4 C394 c* K- f4 t' w2 S3 ?/ U$ z
40
2 X( v6 e& |0 L41
$ ?9 l# v7 x* K/ {6 k3 U3 ]42; [3 U( H6 I' v4 w6 s; d
43
/ v- F' J1 x% ~! B) ~447 R2 l; g; @0 n+ S7 g
45
( x" \6 I; P- a5 v7 s/ Y3 ~46; a4 {, e* ]: e
47
) s9 P" x$ W: {7 |$ D- K! x48
: I9 d/ w a; {7 B+ B5 D3 d" y49
+ f) o, w( q" Q2 N5 T6 o/ z9 B501 w; h" F3 _! ]
51
9 [' e* I" w# a( a' k$ G52
7 E2 ~+ ^- S( t53# m" `1 o7 A5 Q$ Z$ i$ T2 \ C9 e
54, l% T0 J. q! X- U. J* i9 s
55
; }6 ?1 M- Q: F( I56. p) U) R2 b+ E% ]5 G
57
$ v0 W( C, u9 M" t58
) [6 |1 R9 g5 c9 U0 i- G% }9 Q59) l. C; W( n4 _, y
60/ g( w( K! }# N3 f* b# D
61# t' c; i5 W z' P; t. u' F% T
62# K5 \5 i8 z, R
63; T- j2 }" p6 ? Z# m& d) P& \3 O: n0 E
64
3 X& S9 h4 i! a6 k- J; K& U653 S5 l! w' ]; s4 D
66, c2 o# }1 F- h7 ?( b; S* _
67
* N. _( w" t: J* d68
2 M7 z- ]: s, ]69
; p9 I( N1 Q1 R/ u) W) X704 v6 l0 Z+ k7 c6 x2 T0 p
71! {8 x! `) ]: Y" a( i
722 O$ h) p+ \0 c2 c7 y2 v; w
73
% J% ]* S" I1 e74 m( T' ^" K* c" b) N" I1 `! O: f
75) s7 v4 q* s h- d2 c+ A
76- v8 t$ Y/ z, E7 `
77
+ U- G# a) c) @# E4 w78: H! ^$ w3 V2 x1 R6 t8 S5 S0 S2 f
79$ t0 J( C9 d0 i. _- K
80
8 y: v& K4 C8 H/ i; t81- F& @5 y" z" Y0 n: V/ D3 u
82
7 B) [/ F; q9 A" x" m83$ {" }* x- {* o
84
" k- B* R4 z, H- `/ L85
6 Q! b, i% B, m: Z. B( T86
% l' e* j+ L4 |$ z性质
1 D1 O& R% B' V6 u8 [#TOstringITEMS_#; G: H5 S% j, T: f* A+ K6 E7 I1 j
这个宏 是为了: 对类进行输出时 可以直接_cout<< TOstringITEMS_(成员变量...);
/ s& v- b( a# \' D% ?你可能认为, 直接_cout<< ___Debug_::ToStringItems(...)不就行了?
: t* `: N' N( r0 Q f0 y/ F. 错误, 因为在最终文件里 是看不见___Debug_的, 所以写成一个宏 在最终文件里 #define TOstringITEMS_ "";
; T" X* c X+ M
$ ?" P4 E: c7 F笔记
3 [% F4 ]- l7 T9 t" S#以前的debug.hpp#; P7 y0 |( V9 @# [+ b5 U3 j4 q, j
) t5 {" G" N B' ?9 w5 r ~
//{ omipusDebug.hpp& y. ~( r6 S8 e% B# Q
#include <bits/stdc++.h>2 h, e$ ]0 [1 ]1 W
# @# r% g3 l: s+ H5 g3 ~#define TOstringITEMS_( ...) ___DEBUG_::ToString_Items( __VA_ARGS__)
, W+ I( U6 E6 @* s- Z0 z D#define DE_( ...) std::cerr<< TOstringITEMS_( __VA_ARGS__)<< " "<< "{"<< "Line: "<< std::to_string(__LINE__)<< ", Var: ["<< (#__VA_ARGS__)<< "]"<< "}"<< "\n"
- H5 K9 E# }$ j$ V) E#define ASSERT_( _op, ...) if( !bool(_op)){ std::cerr<<"Assertion: ["<< #_op<< "] {Info: ["<< TOstringITEMS_( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< "); Line: "<< __LINE__<< "}"; std::exit(2267);}
) v7 @) |' [( k }# C#define ASSERTsystem_( _op, ...) if( !bool(_op)){ std::cerr<<"Assertion(System): ["<< #_op<< "] {Info: ["<< TOstringITEMS_( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< "); Line: "<< __LINE__<< "}"; std::exit(2267);}
/ N i4 T/ D, j, B) E: |) n; C M5 n, K$ J& b. R
namespace ___DEBUG_ {" K( p+ n: S( g/ C6 M
template< class _t> struct __IsContainer_Unwrap : std::false_type{}; // 所谓`Container`是指 可以通过`for( auto i : S)`来进行遍历的;
. S0 g& B" E I% r) A3 u template< class _t> struct __IsContainer_Unwrap<std::vector<_t> > : std::true_type{};/ N- P3 Y3 b. z$ y' \
template< class _t> struct __IsContainer_Unwrap<std::set<_t> > : std::true_type{};
3 g5 l2 n& j/ `3 H template< class _t> struct __IsContainer_Unwrap<std::unordered_set<_t> > : std::true_type{};& s9 O' F5 r1 K7 B
template< class _t> struct __IsContainer_Unwrap<std::multiset<_t> > : std::true_type{};! z0 h" @; @- I3 \
template< class _t> struct __IsContainer_Unwrap<std::unordered_multiset<_t> > : std::true_type{};
, J7 w0 g2 J1 w7 C3 q template< class _t0, class _t1> struct __IsContainer_Unwrap<std::map<_t0,_t1> > : std::true_type{}; o, ~% y9 I, U4 O+ x
template< class _t0, class _t1> struct __IsContainer_Unwrap<std::unordered_map<_t0,_t1> > : std::true_type{};
& X. J7 B2 O# B, B: z template< class _t0, std::size_t _t1> struct __IsContainer_Unwrap< _t0[_t1] > : std::true_type{};8 z0 a k" S$ x
template< std::size_t _t1> struct __IsContainer_Unwrap< char[_t1] > : std::false_type{}; // 特判, 字符串常量"..."不属于容器;5 @8 l0 w7 t& c4 v9 ^
template< class _t, std::size_t _siz> struct __IsContainer_Unwrap<std::array<_t,_siz> > : std::true_type{};! x7 `8 I8 J6 M3 U' N
template< class _t> struct IsContainer : __IsContainer_Unwrap<std::remove_const_t<std::remove_reference_t<_t> > >{}; // 不能用`decay` 否则`T[N]`就退化为`T*`了;9 \! ?% |/ Z) \$ E4 [
1 q( Z0 _' r, L* Y6 j* h7 T
template< class _t> struct __IsPair_Unwrap : std::false_type{};
( M, T9 g/ z5 R$ e# e* u template< class _t0, class _t1> struct __IsPair_Unwrap< std::pair<_t0,_t1> > : std::true_type{};9 y6 V6 V7 v! {: `9 K
template< class _T> struct IsPair : __IsPair_Unwrap< std::decay_t<_T> >{};
# u2 b; ]6 i7 ^; U6 {+ a* W, {& Z( [) l9 v3 g
template< class _t> struct __IsStack_Unwrap : std::false_type{};+ @* i7 w" H/ k
template< class _t> struct __IsStack_Unwrap< std::stack<_t> > : std::true_type{};
/ T" j% U; A6 C; @ template< class _T> struct IsStack : __IsStack_Unwrap< std::decay_t<_T> >{};
: j2 n A& l1 v, Q, K8 e
P+ d9 I! C. D# a template< class _t> struct __IsQueue_Unwrap : std::false_type{};) D' s& M# y) L: Z, }0 j) U5 U
template< class _t> struct __IsQueue_Unwrap< std::queue<_t> > : std::true_type{};
# v% s. O |4 ^3 i3 A template< class _T> struct IsQueue : __IsQueue_Unwrap< std::decay_t<_T> >{};0 w) ~; ^5 u3 z
# r3 l9 ?, p5 z4 c1 o W- C: h template< class _t> struct __IsDeque_Unwrap : std::false_type{};! D: F2 p* P9 Y" c; ?
template< class _t> struct __IsDeque_Unwrap< std::deque<_t> > : std::true_type{};; ]) O9 K: \' @' [/ S9 O
template< class _T> struct IsDeque : __IsDeque_Unwrap< std::decay_t<_T> >{};
3 Z+ S+ M3 Z6 m: a( i+ I
2 U f0 F- o# x3 Y" R template< class _T> std::string ToString( _T const&);- |0 Q6 X/ w) g0 a
; q* Y7 H& k: B ^6 U
template< class _T, int _Check> struct __ToString_Category;3 L1 \0 S$ M6 M" |
template< class _T> struct __ToString_Category<_T, 0>{ // Single
9 L4 t2 `" s$ W7 Y template< class _t> static std::string TOstring( _t const& _v){
; C: V/ y; T( x! M6 }5 f* A6 v: a std::ostringstream ANS; ANS.precision( std::cout.precision()); ANS.setf(std::cout.flags()); ANS<<_v;
9 j+ G# L" m g$ a( J& i( O return ANS.str();6 @+ E1 y( B( o# D H
}- b- M# y0 W" l! m' k
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;}& i) ]- _% F7 S+ x8 a: M. C, o3 v$ P
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;}. Y( `- l3 B& R3 O$ N/ n1 w; h
static std::string TOstring( bool const& _b){ return (_b?"1":"0");}
, }7 g3 A' k' x* ~ static std::string TOstring( char const& _a){
* y5 a! a1 v; ?, z4 e6 |' c std::string ANS="'?'";( J2 K9 d4 { {* h/ ]5 l8 K5 B1 _
ANS.replace( 1, 1, std::to_string(_a));# _, K4 D, M( z5 N5 o8 O" K) _/ c" z
return ANS;
; q( J7 `: s7 h }
% K9 w+ a& |; S5 v2 r! t" [ static std::string TOstring( char const* const& _s){ return TOstring(std::string(_s));}% p' S4 H: h4 b/ t
static std::string TOstring( std::string const& _s){ std::string ANS="\""; ANS+=_s; ANS+='\"'; return ANS;}
2 B* _# a7 @- u( { p };
! _; l0 D. A2 s: o4 z template< class _T> struct __ToString_Category<_T, 1>{ // Container
, P7 ? a: a2 r I' I: U+ {# t template< class _t> static std::string TOstring( _t const& _v){
# n( b o1 m5 B; o std::string ANS="["; bool first=1; for( auto const& i : _v){ if( 0==first) ANS+=","; if( first) first=0; ANS+=ToString(i);} ANS+="]";: s' _+ M' @9 w6 l
return ANS;
1 }' a* A8 f: p- T/ ?; [ }' \' v/ E2 o4 V+ L
};2 O, j8 X8 p7 @/ B w& s
template< class _T> struct __ToString_Category<_T, 2>{ // Pair
$ C# g, ~0 Y' X9 y; e& ] 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;}! l7 C/ V! _1 P i7 _# v3 {
};) l3 l6 a I6 O0 X |4 @
template< class _T> struct __ToString_Category<_T, 3>{ // Stack0 y8 T9 R) S& h: \5 @: c; B4 u* G
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;}/ E$ U, @* M4 _/ L5 R: Z1 `6 r
};: a% Z- K0 R# l8 k Y
template< class _T> struct __ToString_Category<_T, 4>{ // Queue" e- j, W! o; z- k( t
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;}& E/ c/ O% K" M9 d
};
$ G( D" T' A4 w1 ]# y- m% H template< class _T> struct __ToString_Category<_T, 5>{ // Deque6 G3 F/ b4 q* {: n
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;}2 W7 l/ ]' Z/ c1 {6 o
};2 w4 q( B; E4 L m }
/ B9 E7 @: M9 P7 M; V; X7 ~/ z' [ 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)))))>{};
1 Z! K# Y3 S$ j+ k# ~& b0 z; \! K# Z) b9 w4 N4 C( ^5 N
template< class _t> std::string ToString( _t const& _v){ return __ToString<_t>::TOstring(_v);}: z* u$ w+ Q( {6 E
6 J; u! e; o" i+ x template< class... _H_> std::string ToString_Items( _H_ const&...){ return "";}0 a+ X6 a p, ~! ~- j9 H5 D, \
template< class _H_> std::string ToString_Items( _H_ const& _h){ return ToString(_h);}
4 \1 g& f3 O- |$ ? 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;}
0 e: s2 D0 X' w5 Y7 x! F4 m}0 m4 f1 s$ S" u0 x
//} omipusDebug.hpp
6 X( I% W5 E0 _+ H+ n1
9 P4 U' s' N- F) _# W* I) v23 A! O% a9 X# U1 }3 F9 E
3
0 r' A% T; t' `2 D, z2 x4, ]+ C" Z# I; ]/ a# @
5
+ p1 Q# {5 J% c8 |7 `) n' f61 I' L) L' Q+ o0 p; G3 Q; q% ~- n T
7
! h0 A8 Z' \$ y8" K, I/ j2 x; @& I/ H
9
9 e% t# E" L) Q( T" k8 ]10+ v( b9 a/ V( |0 n2 u
114 o2 |3 h% A& k( C& L8 Z2 K- `
12
9 X# [& i+ D2 v: X) L- o& E* L4 O1 ^13
- p& }& t5 Y7 I147 N+ `4 R$ ^" B+ z7 F: _- M$ S
150 v3 z- F' N6 ]8 V7 X- d1 D( i
16
' j; p t0 F, v$ P) H17' g# c# L+ s$ ]
18
9 @) V* }& y. m19
% _- ~* V- T/ B& l& G T20
6 B- `3 b& w9 M2 d21
8 B1 ~( q, I, n225 D3 z9 D8 C3 ^4 H! O0 d
23
4 w2 ]! C, Z# m* O; v24
& Z0 Q. f2 n& Q25* A8 S' z& z8 J+ h
26
" d* |, { Q' @% e* }278 v9 L- i5 S: u
28 u1 \+ M8 p4 K ~2 d! K
29
8 E5 u. L' I) N: P30
6 P5 j& X6 i$ t: V) ?8 J9 c: J" `31
3 g0 u5 P% C3 m! e! D4 U32
. g. Q' U5 ]/ {9 X, C0 m33
8 |9 j! N3 x0 S" o6 ?1 ]34' X- T- B* \$ t% F8 ~
35) l+ u% h$ z8 |( u% R
36" O" C2 t. S$ l- |+ E) D+ l& s+ h1 K, t
37+ A- S2 J( \7 z) F) a! n4 h( L
383 @2 Q) n, b, d: [5 }
395 R" }, Y9 P7 D S; S- `7 C/ u
40
2 O; r! k) @. t) i: H41& D( o }, G3 v7 U3 R' Q8 G
42
0 d& h# E9 c9 y439 r% S, ]3 S; ^. P9 x. u
44 ^( z D ` Q Z& b8 i
45
( E5 v7 V7 ^& R! d! e46
* I6 |& [4 v0 Z) ~% e5 G47
# q* S& U4 E; T1 L% m& ?; E: J48
& f; n% @3 O& `49! f& M. x3 j T9 j) T- q
50
2 K4 P$ X+ D0 j) O6 l* G1 g" F51% Q, X/ @8 I: E+ x
52
1 K8 F' K+ i" X53! {, K, S0 g# m; Y5 K" \! B9 `
54% U/ Z' f) ], N6 W) |/ I- T! k- _3 V
55
3 H% @7 B! T: \7 z W56
+ {6 w% S8 m* q* h- t5 a/ ~* a5 k57
& }- F, S2 k8 ?- P7 v+ [58
/ Z# d5 O0 x7 ?; n59
1 u+ g8 h& h! K# S' Q60 O f! {* S2 n F( W, z- G
612 t5 p. O$ Q i2 ]' D& U
62
5 \4 p* q5 L7 J63
% e7 K) i) x5 A6 l& a64
8 ` k. m( E' O- ^+ g65
- `3 @% G% W4 }$ e' `: Y& U% ~" O66
V. r; l! N, l" ~+ O5 k+ @* Q67
* i; H$ b1 M1 t& f68( \ |7 G6 R0 Z: Y ]$ u, X
69
\7 D$ U+ y3 z: K70
( \: K% p" }: E! z71
% L. A' E! u5 ~72
' Q3 |, L. C+ ]736 Q, Z3 t5 ?4 m, f& M8 B, n
74
4 e8 s" p, r% H; ~" x' r75
- i- k$ z. L6 B76
' M7 E' l5 r3 ]/ E77
7 L4 G3 i, s# G6 K78
$ Z% S* ]' w6 T& K) n* j3 ~$ {79
& B$ Y' N6 k6 {1 X# w: _" b; G80: [- g# L: k$ m3 x! Y' Q
81+ l* o3 P6 ~) O" t
82. e8 I$ S5 `! T* _/ Y) k) \7 ?! [
83
- u4 L! k; ~' Y- N+ o5 f9 o @84
" b; I$ V' `5 g8 h85 o* t n' c+ q/ h
算法競賽配置
% m/ z3 f, Z$ ]# r' LQT_Creator5 L; E, d5 H B8 _; S* G5 ^8 g
創建一個控制臺應用, 然後在Pro文件裏 添加CONFIG += c++17 (原來是c++11 修改成17); e" p7 W$ D) g9 O+ i+ L
9 v! R6 U; n7 z1 E" q4 T對拍文件% I% f+ }3 m# I' D* O
`compare.cpp`
% y+ I4 _5 r3 U" d S* H: d7 W7 b
! Q0 T. a2 p6 uint main(){
) I) h# u9 H- e) ?9 p. e! }1 f5 i vector< const char *> Init{"build.bat generate_data",' u" F% @, ?0 P0 ]: ?6 O. P
"build.bat supimo",
) a; x4 y' t6 l0 u7 q+ U "build.bat correct"};) C; G9 w1 F: P& n0 b
for( auto order : Init){ ~5 F( e% g" r, V5 Z" F' m5 F/ ]# k
auto errorCode = system( order);; t% V) T5 W' V( ?" H5 g# N
if( errorCode != 0){ EXIT_( order, errorCode);}
; K4 v" d% w1 p, j3 p- f" O }0 J1 `% @( ]8 D; }- {2 P' p$ w
/ q; h2 ^6 p* I7 P
while( true){' M! h7 w+ \8 Y$ v, f- [
static const char * Ords[] = {"generate_data.exe > data.in",
: ^9 `9 Q2 S! I$ \4 n( B8 U; S "supimo.exe < data.in > supimoOutput.txt",. ~, m" Q& m$ v- z5 ^6 C2 x
"correct.exe < data.in > correctOutput.txt",( H0 [- s3 s j5 M- s
"fc supimoOutput.txt correctOutput.txt"};; U* j2 s3 |9 W3 Z* a
for( auto order : Ords){1 ]; r3 ^+ a: _, r/ b3 e- @
auto errorCode = system( order);9 f3 d' q+ Q4 [- d8 }
if( errorCode != 0){ EXIT_( order, errorCode);}
7 x5 F$ K/ A& g0 ~, Q1 }* ~! M. A }
6 n9 z9 W7 w$ w0 \* x+ D, M9 B cout<< "SUCC"<< endl;+ G9 K% f1 j5 @6 w1 G% S; V
}
( p1 f' L* @& g5 z
) n8 c% q1 \0 H( B) g return 0;
8 b9 @ N% Q* o}3 F6 l2 t- `" |
1
' R3 t) k8 s5 n& q3 ~* i2( ]6 n# X5 o2 W/ H$ B
3
2 F9 |6 H' E2 W7 M" ~; l6 |1 w" J) y4, {& Y+ X" n4 |1 l
5
/ o4 c" K' r+ O' k6
3 N* N8 D) {5 R8 z7' L) n( `8 S3 n
8: c0 H- \5 \( k! J, o: y5 x
9
' [) {; |) Z7 R3 |: q10
, b }) [% C* ~$ L+ X! @$ G i11* y+ Q7 h0 c* K7 G9 q3 v- b0 E$ ^
12
- `: k; z% q$ p3 j; \/ l" L138 I$ E! t" W/ i. c7 r$ u
142 x% L4 q- O3 R# [; ^9 c- U" v& E
15
- v3 W! o$ S- C" B2 c+ t4 D) Q& C16
$ x, Q8 b1 B/ Z' \" T2 H171 a# z6 d. A" ~. t& m
18. X- ^: B# |! v9 R; _
19( a) ~3 ^1 ~; }& p8 n0 U; ^
20; | ?3 v7 K; B) f- d# r5 r+ i
21
- H5 _& d" L2 k: F0 l2 r6 N, R/ d" w22
! j) N. d* P1 l# J, u23. q# ?% m; ^ }" x2 T
24; D1 w! h8 p1 m
25
m$ v& Z3 O* w3 ^" g, YBat代碼4 g- k @" f5 L9 e# _9 [1 L, S+ }9 J
build.bat! _( ], W* v$ t
@echo off1 @- Y5 c0 C3 q9 g. [$ _7 `/ s
del %1.exe
5 n0 J2 F9 _6 a' u4 u1 Fg++.exe %1.cpp -o %1.exe -std=c++17 -O2 -Wall -Wl,--stack=268435456 -D"__ISsupimoENVIR_"
; _; r: R9 ^3 r% D" k, l. ?/ U, g+ E' l3 _+ U6 r' E( U k: z
@DELI;: {) P5 u: u0 t7 |5 F7 Q
" k7 U: E+ P8 y8 \run.bat9 q- y3 R2 q/ R4 G7 ^8 `) l* U2 E! T
@echo off2 |/ A& [% b5 A9 l7 V
%1.exe < input.txt8 t- N2 u4 [- f8 B
, D- ?* o7 L* \# L+ t
@DELI;
. }- s: R+ E l% @# ^* x# q6 _
# U- N7 Q4 b2 a5 Nbuild_and_run.bat2 x' X8 d0 d9 H) G/ i$ A) ?
@echo off
; j* b% ^* V8 L' T4 pcall build.bat %1
! c6 F* l3 U# g' A- xcall run.bat %1 %28 H4 p2 R/ G! i+ a7 ~7 V3 [
1
6 u# R$ d7 i( |2 f2" V! f8 }! t: `% S
3: H1 | L# {; j n; F5 y
4
! e6 ?# S. i# v& b$ }51 x* H! d0 E; N+ U- J, F& c% b! y# {
6; ~4 }6 g0 G: `
76 q) j+ N: b* F3 }
80 \! d: q$ V9 P, }2 {
9
' o2 h7 ]( n4 ~( a& l% P6 H0 l& O10
4 t, `$ ^3 n1 s, ?11
- T4 j3 o L) ~2 N12
8 l" {" G# T6 l& G0 w8 f; z$ K5 I! ^13
' {6 U0 \2 w$ s8 k/ _14. \) J( |/ G" K, v3 F! B; D
154 V* J- i5 s) H# I c2 {7 k
16) W& z) S5 ^; u) G5 w. X: G% {
17
' E, E: A% L1 q! E源文件
! [7 C9 H2 J+ L5 }, Z#include <bits/stdc++.h>
# w5 ^4 Q, K" J1 m3 Eusing namespace ::std;* j% E; q1 `) R3 y" R
9 N2 a3 z% z# a$ M1 O- u' b0 u4 f
//{ ___SUPIMO
) X+ o# t6 b1 r; i/ D" V) f0 ]namespace ___SUPIMO{
1 l4 v( ?, D1 G8 T7 Y) r! J//{ Macro6 ~, K/ B" t# Z+ N+ }, 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_;}
. r# F) l6 z* R" g#define ASSERT_SYSTEM_( _op, ...) if( !bool(_op)){ std::cout<<"Assertion_Failed(System):["<< #_op<< "], Hint:["<< ___SUPIMO::Debug_::__ToString_items( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< ")\n"; EXIT_;}8 M; A- g1 x, B* N
#define ASSERT_MSG_( _msg)
8 \% w0 t& m, B$ B) x) Y# |& o1 Y#define TODO_RunTime_( _msg) ASSERT_SYSTEM_( 0, "@TODO: " _msg)
% t7 b8 j2 e* e+ Z0 i# |: J; e#define EXIT_ std::cout<< "EXIT: Line("<< __LINE__<< ")"; std::exit(1);
0 D- }& i& f) F$ J#define EXIT_COUNTER_( _max) { static int cont = 0; ++ cont; if( cont == _max){ string str = "EXIT_COUNTER(" + to_string(_max) + ")"; DE_(_str); EXIT_;}}0 X4 N+ @' d9 ]* T- n0 W3 N! N4 L
#define FOR_( _i, _l, _r) for( int _i=int(_l); _i<=int(_r); ++_i)9 p% o P7 W6 S1 Q& S
#define FOR_R_( _i, _l, _r) for( int _i=int(_l); _i>=int(_r); --_i)
; u' l' z" D3 b6 l0 W#define DE_( ...) if( ___SUPIMO::Debug_::___IsInDebug){ std::cout<< ___SUPIMO::Debug_::__ToString_items( __VA_ARGS__)<< " {Line: "<< __LINE__<< ", Msg: ["<< #__VA_ARGS__<< "]}\n";}% p# g) X G$ C2 i- g3 e d
#define NOTE_( _str)6 ]/ r( {& f- {7 n: N9 ]0 n4 Z
//} Macro; E3 F4 i% Q0 y8 o! h% C/ v
4 K5 x: {5 C. T4 U& K3 enamespace Debug_{
( u" ?8 D/ ~. S$ w0 W, h6 Y static constexpr bool ___IsInDebug = 1;
/ v8 ^2 `2 ~' l0 h2 z 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> &);+ d0 Q# n8 A) K
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;}
' U4 g- M+ L) J1 M6 U} // namespace Debug
' [( }% E9 Z$ q8 } z) L) S
' T( Z* u% b$ _: k//{ Type
! I! i m8 i4 w* G" G' htemplate< class _T_> using Heap_small_ = std::priority_queue< _T_, std::vector<_T_>, std::greater<_T_> >;5 Y% R6 `# L$ Y: u- k# M
) t3 m2 K: T: S' v q
struct Double{
- [, E: m! q/ z( C% K using __Type = long double; __Type Value; static constexpr __Type __epsilon = 1e-12;
4 D$ S( P! R0 J5 Y! m 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;}# Q+ B. _3 `4 d2 w3 [1 G5 o: H0 Y
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);}* r: _- Z. e+ }. b3 l
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;}( [7 B1 A6 H. ^' G X. O* D; l
}; // class Double6 s6 F" W. j1 s
! u( V) B0 |3 D$ ]7 N3 Mtemplate< class _ModType_, __int128 _Mod> struct Modular{
2 G1 j s1 g2 i ASSERT_MSG_( "_ModType_必须是{int/int64_t/__int128}");) }, g, p0 I4 r: D) i8 d
using __UnsignedModType_ = std::conditional_t< std::is_same_v<_ModType_,__int128>, unsigned __int128, std::make_unsigned_t<_ModType_> >;3 A& B& \; ?/ [ }7 X
inline static conditional_t< _ModType_(_Mod)<=0, __UnsignedModType_, std::add_const_t< __UnsignedModType_> > __Modular = _Mod; __UnsignedModType_ Value;; e; o/ x' G, R
Modular():Value(0){} template<class _T> Modular( _T _v){ _v %= (_T)__Modular; if( _v<0){ _v+=__Modular;} Value = _v;}* @2 M4 }& X0 N# J# b8 i
inline static void Set_mod( _ModType_ _mod){ static_assert( ! std::is_const_v<decltype(__Modular)>); ASSERT_SYSTEM_(_mod > 0); __Modular = _mod;}
+ V: `% Z! o) h* f1 U1 ~! m9 k( B Modular operator-() const{ return Modular(0) - *this;} void operator++(){ ++Value; if(Value==__Modular){Value=0;}} void operator++(int){ ++Value; if(Value==__Modular){Value=0;}} void operator--(){ if(Value==0){Value=__Modular-1;} else{--Value;}} void operator--(int){ if(Value==0){Value=__Modular-1;} else{--Value;}} Modular operator+( const Modular & _b) const{ Modular ANS = *this; ANS += _b; return ANS;} Modular operator-( const Modular & _b) const{ Modular ANS = *this; ANS -= _b; return ANS;} Modular operator*( const Modular & _b) const{ Modular ANS = *this; ANS *= _b; return ANS;} Modular operator/( const Modular & _b) const{ Modular ANS = *this; ANS /= _b; return ANS;} bool operator==( const Modular & _b) const{ return Value == _b.Value;} bool operator!=( const Modular & _b) const{ return (0==(*this == _b));} bool operator<( const Modular & _a) const{ return Value < _a.Value;} bool operator<=( const Modular & _a) const{ return Value <= _a.Value;} friend ostream& operator<<( ostream & _cout, const Modular & _a){ return _cout<< "Modular("<< Debug_::__ToString(_a.Value)<< ")"; return _cout;} void operator-=( const Modular & _a){ if( Value < _a.Value){ Value = (__Modular - (_a.Value - Value));}else{ Value -= _a.Value;}} void operator+=( const Modular & _a){ Value += _a.Value; if( Value >= __Modular) Value -= __Modular;} void operator*=( const Modular & _a){ if( std::is_same_v<_ModType_,int> || std::is_same_v<_ModType_,int64_t>){ using __MultiplyType_ = std::conditional_t< is_same_v<int, _ModType_>, uint64_t, unsigned __int128>; Value = __MultiplyType_(Value) * _a.Value % __Modular;} else{ Modular ANS = 0; Modular a = *this; auto b = _a.Value; while( b != 0){ if( b & 1) ANS += a; a += a; b >>= 1;} *this = ANS;}} void operator/=( const Modular & _a){ ASSERT_MSG_( "`Mod`為質數"); ASSERT_SYSTEM_( _a.Value != 0); *this *= _a.Power( __Modular - 2);} template< class _T> Modular Power( _T _p) const{ Modular t = *this; Modular ANS(1); while(_p!=0){ if(_p&1) ANS*=t; _p>>=1; t*=t;} return ANS;}1 l7 L, K5 P5 j) u# x7 ?# Q( S6 \) C
}; // class Modular! E$ L! g: F& }: q5 d, G* W% q9 T
//} Type
+ g1 M2 m% m1 L n8 p) z( E' ]2 w7 Z
3 m) [$ F( g1 D( f4 ~8 Xnamespace Integer_{
( u! W! `1 O! G 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;}
: H; X0 G4 {) ~' w+ \ 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;}3 X: ^% ^1 @, M+ a7 m- X
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;}
9 N; S, A( d N8 ?2 X template< class _TypeRadix_, class _TypeNum_> struct Radix{ // `TypeRadix: 每个进制的类型; TypeNum: 所能表示的最大十进制数的类型`;8 t' {( O( b; o
std::vector<_TypeRadix_> __Radix; // 比如`Radix=[2,4,3]`, 那么所有的数为`([0-2), [0-4), [0-3))` 即表示的十进制数范围为`[0, 2*4*3)`; (Radix累乘值的大小 就决定了`TypeNum`);
% D6 D7 ^! ?; S5 K* V: }: T6 g std::vector<_TypeNum_> __SuffixProduct; // `SuffixProduct[i] = Radix[i]*Radix[i+1]*...`;
5 S' l! o2 K: |" E! \ 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]);}}
9 G3 ]% D: t! V* p n( b. I, v3 ? _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;}
' g9 h$ Q0 {5 y2 ]2 E- y8 J 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;}" Z' Y0 d b7 ~; r- }7 r
int GetBit( _TypeNum_ _num, int _ind){ NOTE_("`ind==0`是最高位"); ASSERT_SYSTEM_( _ind>=0 && _ind<int(__Radix.size())); return _num / __SuffixProduct[_ind+1] % __Radix[_ind];}& v+ e, Y8 J$ T2 u% P) ?
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];}9 y/ D) g8 o# h% C. L. [
};
: y8 j* v9 P& Q' x' `# ]) I namespace Binary_{8 K3 b, |1 j+ e" D" {, P, a
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;}
+ G v: t6 W! E$ w3 B% `$ R4 W 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;}( ]; A6 k4 C6 H I* Y
template< class _T> void SetBit( _T & _num, int _ind, bool _v){ if( _v){ _num |= ((_T)1 << _ind);} else{ _num &= (~( (_T)1 << _ind));}}+ I6 g- O0 B5 ]) l+ N' b$ O
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);}" {* `: c* U( T! l9 r: C8 T" u
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);}" f! C4 A4 S) v. L
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);}
" j) i8 o1 [8 c/ H, B/ h& _, ? 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);}/ ~$ F0 J% P" @* R
// #枚举二进制子集#: `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]` 一定*严格递减*);; k; q9 ]2 t/ ?' }8 f; j! p
} // namespace Binary; o: z1 V" i8 a3 h5 R3 o4 F
} // namespace Integer
* ]+ m' l7 a3 Z$ k# J7 p2 z. Q& C
& B8 P" ?; J0 xnamespace String_{
+ g1 h0 R0 f* F' S I 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);}
& L K- [) t5 a; ?. c 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;}}
( M9 i5 C/ H! f( [. f 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;}. q2 W, s+ B' O, n% E
} // namespace String
$ T0 F4 z' P' a- s8 q; d, p' L- N- l( p9 Z
namespace Random_{: ^9 v' [! B% \, M! l* `# J$ T0 L
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());- e, Y) }+ \ Y5 h5 @- j2 L
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);}9 h7 W8 B/ R" Q( _( A4 W) s" m, Y$ c: X
} // namespace Random. [, ?5 i" U) o1 J+ @. X& H0 P
! h1 u1 y1 |! |& q* v Nnamespace Object_{5 `* w" \. R2 F4 y1 U
const Double Pi = std::acos((long double)-1);
7 ], V5 d: r; J$ u( c+ i 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;};1 g' H$ L! {+ w& I+ H8 f# m
template< class _T_> constexpr std::decay_t<_T_> Int_0x80 = __Int_0x80<std::decay_t<_T_> >::Data;. C9 T% X! i r; |1 F" `6 f
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;};
4 F9 h9 g" G4 Y+ L1 {9 E9 P# F$ F template< class _T_> constexpr std::decay_t<_T_> Int_0x7F = __Int_0x7F<std::decay_t<_T_> >::Data;
7 Z% U" }6 G2 v2 E$ l8 Q; s} // namespace Object: n+ g+ l+ E) z
3 y+ W8 r$ U G( d7 T7 Xnamespace Function_{+ \& w U3 g3 S1 t! t3 U
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;} K$ H/ m1 ]8 R# n- a) S8 t
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);}
0 X5 K: c, x+ M: g template< class _T> bool IsInInterval( _T _c, _T _l, _T _r){ return (_c>=_l && _c<=_r);}
% t6 ~; T3 z9 F- ? p- B/ r3 a 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;}
- I+ x0 P3 r7 M9 ~( n. K4 G} // namespace Function
& F8 H2 g+ v0 x- j. q+ v1 m; F8 G; e! e$ W; }2 t7 B0 ^+ L; j
} // namespace ___SUPIMO7 g+ ?: ^/ H. ?
, D8 o8 H1 G% y2 c' l
namespace std {% c# F7 l: Z& E
template<> struct numeric_limits<___SUPIMO::Double> : public numeric_limits<___SUPIMO::Double::__Type>{};
, E8 z% P2 t" @ template<> struct __is_floating_point_helper<___SUPIMO::Double> : public true_type{};$ J6 o8 r, d6 g
template<> struct make_unsigned<__int128>{ using type = unsigned __int128;};; k0 T5 J3 C, {5 N
___SUPIMO::Double abs( ___SUPIMO::Double const& _d){ return (_d>=0 ? _d:-_d);}2 j' Q# L/ g: c: E, w
}
2 ~" T. I/ w6 u5 x//} ___SUPIMO- N: e/ | K4 k* {2 f* c1 H
0 r, z) P' s' y2 ]7 D- u5 [using namespace ::___SUPIMO;5 j( Q7 g6 X, o% J6 N! e! M
1 [% C; ^) G% P7 Y" Gvoid ___Solve_oneTest(){
4 n) o, L8 Z# b3 u% D9 @
! e# A" }- L! X: C% l7 }7 G}
% i& i9 ?; M( T+ d( X! s: Mint main(){! B) s1 q" g) q( y- g5 F8 f
std::ios::sync_with_stdio(0); std::cin.tie(0); std::cout.setf( std::ios::fixed); std::cout.precision( 9);
7 F; @& `8 p; w. }: q+ Z
/ P9 h7 q W4 Z auto ___Work = [](){ // 必须严格与*题目*的录入格式对应;4 v: C! |$ I% N
constexpr int8_t mode = 0;
x& E3 u9 m! y) H8 Y5 ~% E int testsCount;
# D' r' @1 V2 [, ^. C, p if( mode == 0){ testsCount = 1;} else if( mode == 1){ cin>> testsCount;} else if( mode == 2){ testsCount = 1e9;}! x, Y( l4 s3 R
for( int id = 0; id < testsCount; ++id){
0 G9 h: X4 |; q D- G: O# { ] if( id == 0){ // Global_Initialize
! |1 e4 N) R r
' i) i$ a1 |0 d1 j' y }4 U* V# d) M7 `) X7 e& n
___Solve_oneTest();9 B! P b" ?- o7 E* r3 J7 I
}3 s* u6 W( g- ~7 Z
};
5 z9 y7 ]0 F2 K if( ___SUPIMO::Debug_::___IsInDebug){) P5 X4 k+ P% N1 c: @/ M* p
for( int id = 0; id < 100000008; ++id){) b8 W: U) z3 K, H) `2 g, L
string flag; cin>> flag; if( flag == "___INPUT_-1"){ break;} ASSERT_SYSTEM_( flag == (string("___INPUT_")+char('0'+id)), flag);
; W k* b/ V- @5 b7 E$ G ___SUPIMO::Function_::ClockSplit();
3 W6 n/ G% [. b6 x# e5 Y: m std::cout<< flag<< ":\n";
: W$ w$ o& E% q% p# [( i- w ___Work();
2 v' J5 v6 a6 c t2 _2 [. Q4 _. d std::cout<< "\nTimeElapsed: "<< ___SUPIMO::Function_::ClockSplit()<< "\n\n";) g* j4 Z6 n- j* y- M" V
} z8 M& z# R6 n; x/ w
}
! ]1 c: R' n: o2 w else{ ___Work();}0 n7 n' R, o E# E% i
8 o! X3 T4 h' Z3 k5 v& U. E) `
return 0;! `) x" ]4 k/ g3 |1 g
} // main5 h0 L& F( r8 K3 x$ C! [5 R6 `
' S. y+ U2 ?6 A4 N: hnamespace ___SUPIMO {
* L' {, @- S+ e# X/ B1 j: e namespace Debug_ {1 l2 M. O3 J& a* h4 o
template< class _T> string __ToString( _T const& _v){ ostringstream ANS; ANS.precision(cout.precision()); ANS.setf(cout.flags()); ANS<<_v; return ANS.str();}
7 b1 L6 {2 |2 s3 f5 b 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+")";}
4 t4 m+ \* Q+ [1 c 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+")";}' G# U0 P9 `7 K9 F7 n
string __ToString( bool _b){ return (_b?"true":"false");}4 f/ u5 m/ S& W0 }/ ~3 A% l s
string __ToString( char _t){ string ANS="'?'"; ANS[1]=_t; return ANS;}( n8 A. I* B+ U4 A
string __ToString( char const* _s){ return string(_s);}) W/ O5 p1 S& Q5 ?( X3 _7 Y* ^8 P
string __ToString( string const& _t){ string ANS="\""; ANS+=_t; ANS+='\"'; return ANS;}
6 ?% q8 e" A) ~2 h; G: E 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;}: t; m; _" r9 v) Q
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;}
' w5 m! v4 n9 K7 h9 X template< class _T> string __ToString( const vector< _T> & _v){ string ANS; ANS+="Vector["; bool first=1; for( const auto & i : _v){ if( 0==first) ANS+=","; if( first) first=0; ANS+=__ToString(i);} ANS+="]"; return ANS;}7 J( P& A7 N% z2 ^# w
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;}
+ B9 Y2 I; z$ U+ F; Q8 t3 G O4 g! K. v; | 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;}0 [) |' h! f1 f5 b
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;}
8 h& D) F8 C1 U# r/ Q# r template< class _Key, class _Val> string __ToString( const unordered_map< _Key, _Val> & _v){ string ANS; ANS+="UnorderedMap{"; bool first=1; for( const auto & i : _v){ if( 0==first) ANS+=","; if( first) first=0; ANS+="("; ANS+=__ToString( i.first); ANS+=":"; ANS+=__ToString(i.second); ANS+=")";} ANS+="}"; return ANS;}
' {- y( T: |$ f6 q) n- R1 P! h" [ 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;}
* i P5 `. H- m0 r 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;} x8 Y4 E$ i' ?- E$ s$ |
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;}0 h( j' ~( A2 p- f' I
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;}
* ^2 \: C: R2 r9 K 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;}
$ R3 p' O& R1 x# T- F 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;}
, ^( v- U6 a8 a* @/ N }. [) e4 A1 h& t2 k
} ?; b- M! v, l6 K& i1 m# @
1
( B) l- c8 F6 J) q29 r1 R6 u% U7 E C% O
3
6 g: C3 M6 N" P45 B/ o3 P) _0 m6 A) [6 K
5
4 o; a! K' w5 w4 v% A6, G# Z% L8 q3 ]4 z/ R0 w& v, L
7& N" J( n3 G9 Y: X; l) L
8' F- Y$ S2 |/ d/ j8 z3 i
91 n% b) Z2 i4 W7 h2 r8 v, W
10) B# d( K: }0 R' x+ [* E
116 v0 X2 s) i9 X3 y3 K/ ^5 H2 x. t. w
12
& v& w6 c6 t- @9 P13% }* x; J. e( [: ?9 i- ^& @; o
14
' `6 M/ F( h. D( U+ N& F6 { ~$ v156 [7 z6 ]/ n$ Y& g2 A' m+ G; l
16
4 k. |: H. r! \ U5 }: L17
, `$ A6 W( G0 a9 R18
: i: C4 _& T) @: {& p19
5 A/ B4 C. {" l3 P20" W2 }- I! S9 I' o! K# B
21
) e2 @) R6 k4 Q# A: j8 O0 F22
. p3 _6 X' w& U# o2 r23
7 R& N1 ]" R) q" _, r+ X% ^! D! g24
! w. I N ^; Z/ _/ e25* i8 [- l0 j& y* _, }9 }
26) s; n8 t/ S# H7 _. e; R, \
27
8 |" T6 O. J7 s9 C& W( E2 K) Z28
: r% L) u) W9 Z" v* ?* l29
# \" E/ F7 m3 t30% @- N W/ f* h& H' O
31
! c! S' e6 U2 E# v32) F, v5 p7 \8 r4 ~
33
# I1 D: Q. j# e. `# V34- l: h5 A" y2 ^( h
35! p- h6 K, p6 ?8 H; J E
36
) M5 t: T/ x$ i$ z; W* e374 Q7 [/ Y: m& |6 {- C {
38
8 c8 Y& L& `- W: k, N39; H' ?( H0 V X4 \
40' o5 G6 @- ]: i% D, E8 L
41
. z2 S7 S, G& j2 t0 L# x42
2 h' E; b1 k u) h3 k: [5 J437 w E: t: I$ Z& N' |% H
44
1 J, L+ h) X: ^45
, ^* `+ B: X; f' W3 y1 Q46; p1 K' M: z# i; u& n9 L4 B) x/ {) Y
47+ U: a" }. ]% W4 t2 D
48
7 h! Z2 s! ]" m; v1 Y0 s. p/ ]497 u8 b$ }7 {& X
50# H3 ^3 D; x6 A' ?7 c
511 f- r& Q6 N' ]; l% ]5 _/ ?
52
6 s4 }# R9 e: N0 }- m- u' X, Z: y53
; u$ V0 o& d7 E o5 B& \& c54
% |8 D2 m6 I! l" h: B8 ^55
( R5 w5 ?0 H9 M0 o! L8 y56
0 a# M/ ]4 Z8 V2 Y1 y57
5 J1 c& t4 J1 f; K; R1 ]9 _1 o+ A: R58
: m. u B; \' c, W59
$ ]- ^; }* l$ d# ?602 ~! l! ~/ k0 o8 ^
614 \3 u( |" X9 v. f+ {1 \+ ]0 I
62' ]% g: m2 j: }: s3 [$ Y( `
63
6 g( |- `6 e: H& |648 w+ @4 u0 G) e$ Z
65
$ M B: W# r: |' ^1 k66
2 [# F/ d* {$ J o67& `. h* @$ y: @+ x
68
3 I0 @. G2 Z- ` ^69
- g ?! L+ W0 C+ ^6 s% j) a$ L7 x704 E9 K& T, }/ L: |3 L0 E
71# B2 D. e6 Z" T8 ?8 v, ?
72
& U. h" ]& S$ i73' L$ ]( m3 d g$ S0 I
74
& {. y4 [1 l) U1 D9 T759 F% A* X) F. T
76' g7 d" I2 F) [8 {5 l4 i) Q
77
- {3 ~/ b* d' y( b# P78, d7 C3 {8 V- L( W7 J
79
+ ]: A# O4 }, R+ c/ k6 h% m2 q9 V. K80
/ {7 A, G' k! }0 |+ O/ z. B811 w+ o# T6 b2 ^8 ?. \/ ?$ G8 o
825 k) S- R5 T' \; v l# ]
83* c% A, W# C7 d. B% S' h2 e( b
84, H3 x* [$ I! f5 Z; W5 M' C( B) D/ K
854 k7 n* ?( {+ ?7 U. R) G1 t1 p
86
) z+ `8 h$ s$ i- E9 Z8 \87. w9 R/ B7 O x6 q
881 G7 b" d& z5 t, x# i' @* X9 D( v
89+ k, n! z, Z( W5 t1 }2 V
90+ C# N& y# h$ k6 O9 t) x, s6 S. S
91
p+ V2 J9 L. ~# {3 n927 p% z ]% a! `
93- n( `: }4 S u: N3 z9 Q% g
94
C- X- P+ Z B( z' T/ i1 v! e952 l$ D8 j& ]9 I$ E" H
96
1 S, e+ H1 V4 ~: P) b- _6 L97# @& _# w# T" f& D) j+ _
98
2 M% v" @: V w c& A& W6 p8 K s1 n0 |99
, T$ p/ a* x; Z4 X5 ~ G1005 S) d5 j5 V; A: j) Q1 L
101' l4 v' P) ~' n' ]
102: P! p3 Q+ Q+ ~% f6 D' {
1039 J. ]! {! U' E0 v' L' y% @9 T w
104
+ p9 ~& W: U) [% T* @6 r105
8 j0 s, a% u% a& Q2 o. A106: v1 C8 L* E( H& C2 M% d
107) h9 i8 H- Z2 b' b* a4 ]: H
108
3 S3 U9 M' W4 w* n6 @3 I" k1093 `. Z& W k1 h9 Q3 k( Q
110! j) i" v; E2 h3 @
111
4 _% p) o9 P" G112
; H# v R! {1 V7 Z6 Z3 v* c1 H7 w1137 x0 p- E/ T5 W% |; P
1146 j2 @3 r1 B, K; b, ^! P" }- L
115
1 X1 S i4 Y) a! y; @116+ F/ h1 C. M- J1 g! [" f4 O+ O
117; o4 x4 x0 E7 J
118) f e- U* d- v% S* W) c7 n/ {
119
$ X0 |2 O$ z9 |/ Y, b120/ ?% [$ t3 w- o% h' A3 g1 [. T5 O& r
121
1 e8 K. B+ J6 G$ ^! ~9 I1221 P1 h" n/ \* L/ {, D* I
123! s. d: ^% Y& Z) R* i7 E
124
/ e5 A1 l1 D# n* @125
6 K: V D" W2 d% s5 y$ ?4 v. [126
1 T* W0 I1 d5 B/ O4 h127
. n9 M. B+ Y$ U9 @8 p: ]4 D128
+ L* x; m% {: l0 j4 }( P) U$ k129% S+ Y" S! o3 l! ^# T5 Z3 ?, [3 _: O/ _
130& {+ N! i9 j3 B
131
& K& {0 H; K, _132
( p6 {6 _- c' ^! Y1338 W1 @0 b4 h7 X8 t
134& O: a5 M" d3 I4 X x; ]6 m/ q7 U
135$ F. U. U3 p9 s8 P
136 j- M, y; g( _
137/ S& P+ [% R# C$ Q% j1 ^2 M6 w
138- a, v8 j* g: e' t5 u
139
, R2 [8 C8 h; m/ v# c1 Y0 P) @, D140- _9 Y+ S! H% h8 X: j" [
141
7 D' p9 Y: l, h/ l+ ]. R# j% Q142
" h+ p( q9 h( Y9 |0 \7 F( V143 G& J# v: ^6 x. f. \$ I/ \
144
' x0 P# J% `' }; m145. i' D3 T8 d2 M5 ^, Y2 l3 b: S
146+ S! A1 q* N' V h7 ~
147/ _* f# H9 Y) c3 f7 ~* F3 Q# H8 K
148& j7 {& ^2 F; d
149
7 F( c8 ~) q' x) Z6 [# U9 ?150
9 o, k2 h7 u& N/ H3 I3 Y151
+ V3 E7 I6 ~0 }& Z+ I0 q3 t1 `152# `0 q B& T2 \( q6 r% |
153! s6 C' F4 B. F5 R# |' H: a
154+ z; Y) K' a. ?& y [9 U: n
155
0 Z, \1 t- Y, {! W5 W5 }156 q V+ F5 V2 `' G7 Y
157
' n, l, g1 v" R1589 g6 n& g- l# S* D& S
159
' E9 N, Z% B9 J1609 E- @+ S0 H$ D8 S+ D5 T
161
4 n# Z7 U; {7 a7 O/ j; K( j- h/ k# j1623 q- M J9 W; E% a! W! u4 `( f$ @
之所以把___Solve_oneTest()單獨寫成一個函數 而是放到main函數的for循環裡面, 因為: 當我們要進行特判 比如if( N==0){ cout<<"YES"; return;} 這裡的return 就是結束當前測試, 可是 如果你放到for循環裡面 你可能認為 那用continue不就可以了? 錯誤, 因為如果你內部還有for循環 這就出錯了 即此時continue不是對*外部的for循環*生效; 所以 必須要寫成函數形式;; O- y6 L# k; U8 V+ P* k
. K$ c) w) f5 s0 b4 f% A
Global_Initialize* h, e7 O! e8 Z" }+ {3 K. a5 v$ v
专为力扣设计的, 即全局(多组测试数据所共用的)数据的初始化;
/ g, C# u, F% x, M; }
8 M1 ^4 s# Q6 f2 ~2 `' l! g3 s0 k: rString7 F4 t; v) o z; ?7 j: L
Split的答案 一定不会有空字符串;7 a& m! b- @- I" j/ i" r
他是从前往后贪心进行的, 比如"xxx" 以xx分隔, 那就是[xx] x 即答案是最后的那个x; 比如"xxxx" 以xx分隔 那就是[xx] [xx] 即答案是空的;( t% g; j" e7 d
7 r, X- x( Z3 W' Y5 l
@DELI;
8 o. N- t' |* J* b: W' `: s
! W) r1 B3 e Y, c: QReplace的本质 就是Split函数, 即比如你Split得到的是? X ? X ? (将X替换为Y) 则答案就是? Y ? Y ?;1 b0 O$ m1 R2 p$ |1 g" f
. 比如S="xxxx", raw="xx", new="x", 那么答案是xx, 即先是[x] xx 然后[x] [x]; (并不是[x] xx 然后[x] x 然后x);
* c9 c k. D! N1 A2 c/ R$ G" v) g! z% {& \4 @7 M
Debug
, ^% P. ?# l* ?) J! W, Nif( ?){ Debug::__IsOpenedDebug = 1;} 和 Debug::__IsOpenedDebug = (?); 这两个 是不同的!; D/ z0 x" n/ a4 ~, ], w
前者: 他是在特定情况下 打开调试, 但是他不会关闭调试; 而后者: 他要么会打开调试 要么就关闭;
0 o+ n e% A" J" y前者 通常用于 针对某个子流程而调试, 比如... [T] ... 最开始我们关闭调试, 然后到[T].入口时 打开调试, 然后到[T].出口时 关闭调试; 即整个过程 我们就调用了三次IsOpen = ?命令; 这通常在DFS时 使用的较多, 即符合某种条件时 进入某个DFS分支时 打开, 然后回溯回来时 关闭;
6 C4 t% M9 {. X0 I$ q2 M' Y4 K而后者这种方式(即不停的根据条件 打开/关闭调试), 一般在非DFS的场景(比如FOR循环)里 会使用, 比如只对所有奇数进行调试;8 v" [& c f5 C" P
即前者 他是针对一个连续的子段, 而后者是针对一个序列里 满足某条件的若干元素;
, X, k+ [4 R3 K" Y9 s- w) H$ L8 k- }+ R6 j9 T6 X
@DELI;
; w9 h* e1 ]0 a
+ S5 v, S2 R3 w& [! b1 W有個疑問: 為什麼要把他轉換成string 而不是直接cout輸出呢?' _4 o1 e% Q0 \) R& `
. 可能是多了一层封装? (但毕竟你这个模块 就只复杂Debug输出啊 有必要再多封装一层吗?
+ n; I% D1 W* T8 H/ ^: q; _3 Q$ _. t# E& {" M$ R
@DELI;
+ _% |0 F! T% p: F$ g$ o* g, K+ Y0 B: w0 X4 H
INFO_里, 不可以对#__VA_ARGS__直接用,逗号分隔, 因为他可能是INFO_( F(a,b), 3), 所以你还得判断括号;8 x. T2 H2 C( I# Z+ m
7 a6 }0 h }5 K2 H8 j' o
@DELI;
2 w, Z: w3 z0 Q/ A; }% |6 W" `! B; O0 Z R) h
T A[10];數組類型, 你可以直接輸出DE_(A);
: a' ?9 m& Y+ k& R) bDE_( (T(&)[5])A); 這是輸出A[0,1,2,3,4];
& _0 c7 ~# k3 G' b5 E- b- P$ W2 |0 d6 x& Y; s/ k
auto A = new T[2][3] (此時auto == T(*)[3]);
$ C8 I7 j/ g. Y: k6 D: a, @1 V ]& K. 要輸出他的所有元素, 此時直接DE_(A)是錯誤的(他是個指針地址), 正確語法是DE_( (T(&)[2][3])*A), 注意 *A的類型是T(&)[3], 但你把他強轉給T(&)[2][3]是可以的;
' {) q7 i" l$ y: T& y6 `
, T0 q* ~8 ^4 @2 x& B; V7 e, t1 \@DELI;5 C/ Z$ [# `7 T1 `" p+ ^
- ^% a' U5 u4 u! J__Debug_list的參數 必須是const _H & _h, const _T & ... _t引用 不能是值傳遞;. L8 V, h9 Y* x5 ~2 e
比如對於對象很大的情況(圖 本身都已經1e6級別的大小), 那麼 這已經不僅僅是效率問題了, 因為參數用的是棧空間 這是會爆棧的;
' s$ l" R5 R8 t
7 ?- J3 b' g3 z" k@DELI;! a1 n2 m) K0 I, G1 w6 Q2 w6 ~
" P* r: j' H4 J' z; o我们使用__Cout自己的重载函数 而不是去重载operator<<, 一个原因是 对于char/string基本类型的重载 此时和系统的就冲突了 (你需要再单独写个函数使用is_same去特判) 所以 不如就不使用系统重载符了 直接自己定义函数; 第二个原因是 其实把 两者本质都一样 我们自己写个__Cout函数 等于多了一层封装;$ @; T* P, F" c
5 T1 u u0 P( H: L: }4 R! `你必须要声明/定义分开 這是為了實現對嵌套的輸出, 比如对于vector< map<int,int> >的输出 他使用了Cout( map<int,int>) 因此 你必须要有其声明在vector實現函數的前面;0 _6 y! d8 g! D N& ?1 p& S& Q
9 R" w* y2 Y7 i. C如果是自定义类型 他会进入到Cout( T) 然后调用cout<< T, 即你的自定义类型 需要有重载运算符;
& k& [; T) w, v, \% s4 p! I* n. a6 {9 R- O/ m5 S7 b
@DELI;
5 i# g( E ?' V3 r* p+ h/ u0 A! m9 O" B/ Q2 b) a
__Cout你不需要寫成 像ostream& operator<<( ostream&, T)那樣, 直接寫成void __Cout( T)即可, 這是因為: operator<<之所以要那樣寫 他是要實現cout<<a<<b<<...這個操作; 而__Cout 不會調用__Cout(a) << b這種操作;
$ A0 h5 V* L) G9 N
1 u, r& P& z. `/ _ASSERT報警宏3 M! x+ B3 r6 i2 w2 n5 {" y7 U
#如何关闭某个子模块的ASSERT$7 v' R. }9 N: u/ }8 F
对于算法模板A, 他里面有很多ASSERT_SYSTEM, 为了优化效率 如何把他们给关闭掉呢?/ M9 E. V4 P3 S8 { i0 k! t
b! ~5 M. r; _5 |: c% v% h8 ~* m#undef ASSERT_SYSTEM_- Z5 f* r( d: j) {6 W
#define ASSERT_SYSTEM_( _op, ...)1 F' S$ _' K$ {6 Z" _+ J! f
namespace A{5 i& A# b& q/ T/ G0 W0 V7 N+ \
}" `! a( S5 _$ G3 z
#undef ASSERT_SYSTEM_
+ S% k1 [4 u6 o( k N, O: k) u, S6 o- s#define ASSERT_SYSTEM_( _op, ...) if( !bool(_op)){ std::cout<<"Assertion_Failed(System):["<< #_op<< "], Hint:["<< ___SUPIMO::Debug_::__ToString_items( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< ")\n"; EXIT_;}
- ]3 W% F' |5 G# X& c5 ?1, P8 H' V5 V4 `% z
28 K/ f. ^5 T$ j6 @7 q7 r/ v# v2 m
3 y) G9 j$ N! G @
4* n1 v; a1 [/ K
5, I( t0 B3 q8 G9 x4 j
6
! R) A7 n) T8 o) b/ y4 x. 也不可以不写#undef, 但他会有警告warning: 'ASSERT_SYSTEM_' macro redefined;6 @2 L% L( t' y0 t3 n) T
: {# |4 g8 y/ T) i- d6 e
@DELI;
6 U' x% _4 j. ^5 B$ o1 A7 |3 W$ w! b( m$ ~6 M
ASSERT_CUSTOM_: 用戶自己的程序裏面 使用這個宏;
& ^4 b8 H; S5 M# u ^ASSERT_SYSTEM_: 算法模板裏面的報警 都使用這個;; b- p5 E% v. I0 x1 M1 O
& Z! X" ~" @3 P# { D: V1 }5 c
宏) p# T( D& \: y1 x* K+ {
為什麼FOR_的宏定義是 (int)_r呢?/ S5 ^6 z$ D3 p
對於uint32 a = 0, (a-1)的值 是111...111, 於是for( int i=0; i < (uint32)-1; ++i) 這會死循環的;, c. z u' I2 r: x2 R' C
但是 把111....111 強轉為int, 她就是-1, 即int i = 0; i < (int)-1; ++i) 這是正確的;# R. B$ l1 b; _/ U
. A" n% Y$ Y; L) P4 H; C! E2 Z
@DELI;6 \" z( a8 e s, f* D" V+ h: y
% o$ m$ o) ]$ F* i3 g0 V這3個報警宏 都有2個模式:
- M! U, C# A: U/ n `* K& Y) g1(默認模式):[如代碼所示];" p; y0 ^) d6 p' J1 `
2(優化模式):[你自己把他注釋掉, 這主要是為了(提高程序效率/便於找到程序BUG)];; K2 G/ a5 m0 q! G! W
. 比如默認版本是#define A x, 那麼你就把他改成#define A (void)0 // x, (注意後面的注釋// x是不生效的 預編譯時會被清除掉 即到時候是(void)0; 而不是(void)0 // x;)& u7 q' O* o: A# Q' ]4 o/ I+ Z7 R
5 G; a: `% p7 A$ b
ASSERT_MSG的優化版本 即static_assert(false), 此时在开发阶段就會報錯 也就是你會發現所有的調用ASSERT_MSG的位置, 就可以发现有可能存在的错误;2 B' ~! P% T, Z9 y# I( f
& b4 R$ v5 F! L: l) {5 y8 D@DELI;% Z- L1 z" y4 A) t5 z
0 _& P5 }% P$ L; y. [* z9 `#ASSERT_MSG_( _msg)#9 s0 c, h' s& e" I9 o
这是完全给用户提示的 程序无法测试其正確性 但你自己必须保证他是true; 比如取模除法 mod必须为质数, 就可以是ASSERT_MSG_( "mod必須是質數");
' I+ \7 k0 B9 r2 P D6 O: Z) y* f- k# |9 {8 p
@DELI;9 s2 \ K2 n# _0 j3 Z8 C# n* x
) f* A1 D( ~% x9 g* ?; x5 ?#ASSERT_WEAK_(op) (void)0#
c- Y" `9 }# H9 I) U* i" I即使op为假 也不会报警, 但你自己要保证他一定是true 这是为了效率;0 l; z3 a, s1 v/ s
5 {" F- v7 G$ o' U q' s- i; QModular, U% a& o! i+ l# U" T) x6 e" ~
Modular的設計思想是這樣的, 她有2個模式: 對於using MOD = Modular< T, X>, T必須是有符號int/int64/128;1 J9 c; P0 {& I$ [" R
1: 你的Mod模數 是不變的const常量, 此時 這個X是常數, 即在編譯期 模數就固定了;
' q, h5 |! y0 M, `. G- w2: 你的模數 是可以改變的, 此時這個X <= 0(你任意設置一個值即可), 此時到了運行期 你可以動態的通過MOD::Set_mod( m)去設置他的值 且這個m參數的值 即模數 她必須是在T的正數範圍;: q8 n9 g- s; l5 D7 m1 q& C1 E
不管哪個模式 假設你的T=int 你最終的模數 一定是在[0, 2147483647]的範圍內的 (而不是uint32的範圍), 而且你的值Value 一定是unsigned T類型, 為什麼要這樣設計? 因為 當你進行加法運算 此時 你不需要轉換為int64 她的加法結果 一定是在uint32範圍的;
; t9 i( X4 t/ w! I, B6 W: B: u" s+ i0 L
@DELI;
8 S2 d$ F6 w, U% l% H) K' ~( ?8 l, x1 f |4 ]4 Z1 K
對於乘法操作, 如果是int32/int64 則直接轉換為int64/int128來進行乘法, 否則對於int128 則執行二進制乘法(她會調用取模加法 是不會溢出的 這就是為什麼你的模數 必須是有符號範圍);/ r# A- p8 B1 w
6 L7 p9 F; U. }& u, w9 O9 W
@DELI;, ] F8 N0 G5 @* ?3 R8 H0 A
! Y$ k# e) V! j, Xtemplate<class _T> Modular( _T _v)這個構造函數裡 你不能對他進行is_integeral的判斷, 因為對於__int128 他不滿足條件(可能未來編譯器會支持 但現在他的返回值是false);/ K5 [: t, ?) j' E# K8 {
& Y$ T( \$ k9 S4 k" q& [
@DELI;
; i( `/ \; j0 Z
8 \3 i! ]* t0 @* g. f1 ]8 Z基本使用/ u5 K; _+ R! Y# q+ C3 P
6 l' ^' w! l& b) w
using M1 = Modular<int, (int)1e9 + 7>;3 L, h! c2 _- P: J, z
所有`M1`的對象 他的`Mod`都是*int常量*;' f$ ^$ X9 `; O4 S7 w& R
7 G# I* d* V3 Z) j5 susing M2 = Modular<long long, (long long)1e15 + 7>;
4 q, e: M5 v, ?! ~2 I6 g. }所有`M2`的對象 他的`Mod`都是*long long常量*;
* Z: x0 ?. U. O; N
0 c2 X6 j }( [: vusing M3 = Modular<int, -1>;+ @1 O8 f. U# @0 i1 w
M3::Mod = ?; // 由用戶錄入 (這行代碼必須在*運行時* 即放到函數域裡)
. S# Y% Q: U# Y9 ^+ c所有`M3`的對象 他的`Mod`都是int類型 且等於`?`;6 O* A) D- N, A( G# k0 I7 s/ B
- N# l; c5 Z- \3 s3 o
using M4 = Modular<long long, -2>;% c( S( {1 S( `2 U) o7 A" C3 W- E
M4::Mod = ?; // 由用戶錄入 (這行代碼必須在*運行時* 即放到函數域裡)
6 L6 M0 W z: f/ L所有`M4`的對象 他的`Mod`都是long long類型 且等於`?`;
* |8 }1 u/ u( l! ~) H+ M& l: p7 U/ m" p
using M5 = Modular<int, -2>; // 注意此時要和`M3的<int,-1>`區分開來 即不能寫成`-1`, 否則`M3,M5`就共用同一個`Mod`了;- J' e. d3 M0 c8 F7 T
2 J6 c- @9 _+ ]" D' U4 Z! P
9 w; _' |& Q Z6 |- M: z@DELI;9 G' q5 i) K% @3 @; d8 v$ X# z2 E+ Y
% c/ J9 V. D' ?2 d8 G* [
T_ Value; // 一定是[0, Mod)范围; 不要调用`obj.Value = xx`(他不是规格化的) 而是使用`obj = xx`;# x: f1 ^) g# X3 {6 K
15 q" b1 n; D* ~( p; S( D
#除法#% N6 l4 }9 j# F! w7 p. c( m# H" Q
调用a / b的前提是: (1: Mod是质数), (2: b != 0);
0 G; }; g/ T0 ~7 }: ^5 j" y# `$ B3 f3 U
@DELI;5 e& t) L3 B/ l# y, }# f
+ D; l" `/ u' P7 F2 _3 C
#BinaryMultiply#- y1 Y: D3 h' c: ?& H
使用a*b(重载乘法)的前提是: Mod * Mod <= INT64_MAX; 如果是Mod+Mod <= INT64_MAX 就不能使用重载乘法了 可以使用当前的二进制乘法;; v! _" Q0 V# N1 C1 v0 @
5 Y! f8 e; v! s* Y2 P5 e( M@DELI;
2 H5 E: l0 N# Q/ V6 e4 p7 H$ {1 b0 v' g% F3 B
#__Cout#
' D6 r7 s( s' k这个函数的目的是: 特判, 即对char/string/const char *的输出 重载, 之所以不是放到<<重载运算符函数里, 是因为 如果是<<重载 这些基本类型 就和系统cout的内置重载函数 冲突了;2 z" b/ O% O" L2 c
也就是, 比如对于vector的重载 是放到operator<<里的, 而对char的重载 是在__Cout里;3 z' |9 U# N @! r$ T3 f# K' x
7 c) z' n: @% Z函數
6 f, e3 p; F1 l D. [$ T$ Y3 b9 M#IsInInterval_#/ m3 p( T% v: d2 |& B5 g2 ^( V
. IsInInterval_(c,l,r, true): 判斷是否滿足`c>=l && c<=r`, 即在這個區間裡;
0 V# l% t6 K0 c7 B, E2 t( `# w. IsInInterval_(c,l,r, false): 判斷是否不滿足`c>=l && c<=r`, 即在這個區間外;( @" s9 j0 t& F9 ~
1
d" i/ Q& I$ S2 k2
4 U! V2 @. Y% H0 H- f7 l3
+ r1 ]+ Y9 Y! `. L# X# i8 CInteger7 b! ?6 R, c1 \: |: K
GetPowerRoot( a, p), 比如令T = a^{1/p}, 则返回值为T的下取整;
" Y, `) n) e( H; ~4 `1 y7 }" U; \ z- _+ q. C+ n
@DELI;6 W; @$ K3 o! S
& @" Y; k( T1 |$ j& o! G g2 D7 ]VectorToInteger和IntegerToVector是互逆的;. j- N. h, q8 p0 }+ m( i0 }* r
數字的高位 就對應 Vector的開頭; 這樣設計是因為: 對於一個整數321 我們通常是從高位開始閱讀 因此高位對應vector.front();, K: y8 }$ g2 m4 y2 ?6 T5 f5 g- @
. 比如, 整數321 (3是高位 1是低位) 她對應的Vector是[3,2,1] (3是開頭元素);
$ y6 N* J8 m, k6 _- p# U
& C' n. I7 a% d/ o" Z@DELI;
" `9 ]5 h9 [+ g, k! _% H
0 T9 P3 E$ W; o5 c2 m使用该模块里的任何函数 都是谨慎, 最好就是在调试期间调用, 你要充分考虑好他的实际效率问题;( \" S+ N& ] k- |
比如VectorToInteger( {a,b,c}, 5)这个函数, 其实 你可以自己手动写成a*5*5 + b*5 + c, 没必要去调用这个函数, 因为此时你已经得到了{a,b,c} 他的长度是明确的 去调用这个函数 反而效率非常低;
$ t/ H) s+ t1 n8 i/ q% c K! N! y
/ @9 e$ v7 m; H( Z1 l; n@DELI;: v) c; R6 @* \" e8 j. ]0 u3 b
7 q6 q3 r d% y/ k/ c R7 T0 ?8 Tvector<int> IntegerToVector( _T _a, int _len, const int _radix);
7 j' P' B; m. {% m# e% I) x比如a=10, radix=2, 他對應的2進制表示為1010, 那麼此時你必須保證len>=4 (否則會報警);
! W' U- n) l' A& y5 v% D9 n2 b& A. @IF(len==-1):[答案為[1,0,1,0]], @ELSE(len!=-1):[答案為[0...0,1,0,1,0](即前面補充前導零 答案長度為len)];
$ V, |9 }) j$ m
; b, c5 y! p+ f* W2 u4 K7 o@DELI;9 o% m6 d) r( Q' b, C' {
/ i# A& D( `( Q% L* F- I9 QSqrt( a, p)
) b) u# t/ u2 J4 {9 r0 F要確保a>=1, p>=2, 假設答案是浮點數b 且返回值是b的下取整;8 ?1 @; c& R9 G4 e6 W1 j: i1 c
這個函數的主要目的是 判斷a是否是p次冪 如果是則返回其p次根;+ z3 W; B$ w! n+ V5 b
. 由於b = pow( a*a*a, 1/3), 此時b可能是a-1/ a, 而答案是a, 所以要判斷 是否b+1 == a;
5 {" j% c) X4 F( o: f D$ ^6 u% Q5 [. Y9 X5 g6 @9 X+ Q( r1 h
@TODO% }& L( K* g% ~2 g7 Y; O" d7 }: Y
Modular里面, 我们用unsigned T来存储结果, 但实际上 你的取模值 一定是[0, T)范围的, 即只使用了一半, 这是因为 当涉及到+-时 此时不会溢出;0 {; w9 O l" E7 }8 y
. 但这有缺点, 当你Modular a = -2时, 此时构造函数是-2 % 5 他会变成int % uint -> uint%uint 即-2会变成uint 这就出错了!!! 因此要写成int%int;
: A `: X0 x/ ~( I" b最好是, 你就用T来存储结果, 当相加时 他虽然会溢出 但其实他还是正确的! a += b; if(a<0){ a -= Modular;}就可以了;
7 |- U+ F$ S$ E7 F" k3 _$ F5 v2 T& d. S
错误
+ h6 I5 ]1 B! O5 v# Gis_floating_point_v< Double> 他是等于0的! 因为Double是我们自己的自定义类型;: g) b! x' ?. b; S+ X
你可以写以下代码后, namespace std{ template<> struct __is_floating_point_helper<Double>:public true_type {};}, 此时 就可以了;
5 G% W* t4 c$ }6 K4 _1 n' G4 y3 \9 U+ m% V' N
算法模板编写规范3 Y3 h# ?5 n1 J: j' O: N! A6 p
错误
7 ]" s( K/ i: B* D模板类 不要写构造函数, 因为我们可能写到全局域里 ST s(而不是ST s(??) 此时不能有参数;
. f8 G. P/ G) y5 u1 f! f' S: p. b; w
@DELI;# ^) t/ E: {$ A. i& t* K6 a
9 J/ V* s- M, b0 U# I! t4 q
不要写namespace ST{ using T = ?; vector<T> DP; void Work(){}}这种代码; 这样会导致ST是一次性的 即T是唯一的; 然而namespace不能加模板;
1 ]7 _# U' h) G3 A$ Y一种做法是: template<T> struct ST{ static vector<T> DP; static void Work(){} };, 但这样有2个缺点: (DP需要在类外定义 因为他是static), (由于ST是类 而实际上 他里面都是static的 不会用到他的对象 这就违背了类的初衷了);+ V/ k/ a* ^! `2 j5 l
最优做法是: namespace ST{ template<T> vector<T> DP; template<T> void Work(){ 使用DP<T>;};3 J" i. v+ o) Q/ |( Y+ @9 W+ X
1 C- s9 w/ _! c4 n) m& C性质& t6 B5 O7 a" z* q5 l
模板类里放大数组constexpr int N = ?; int Arr[ N]; 等你用到时 再把?赋值, 这种方式 他确实是效率比vector<int> Arr要高, 但有个缺点是 你到时候的类对象 就不能放栈空间了 需要是static ST s 否则大数组就爆空间了;
: b& }; e, b9 t/ Y% Q3 T0 i- m! e& I
@DELI;
& ?; y9 E* h; D. }$ k' Q9 N. l4 p9 `; d6 |
不需要寫一個TODO_STATIC_的宏, 對於靜態的@TODO, 你直接寫成注釋即可: @TODO: xxx, 然後實際使用時 再把他給注釋掉即可;
% Z: F4 Y3 C3 h' d0 t/ a6 G5 O$ V3 j& C. l" j+ p; g
@DELI;. d7 |8 g& `3 w4 v. |
5 _' ?8 F- f- u( l% _3 A" |- @' J#讓某個函數 必須在程序開始後執行一次 且只能執行一次#
2 ?, K9 W( W1 C, @- Q# |' J; \" v
void Init(){
' ~1 N: d: C+ R7 Z" m% W" } EXIT_COUNTER_(2);
' y9 l8 ]/ ^) Q, ?}) `) \3 ]- O {* r
@TODO: Init();8 O' B2 F4 C) G! f' j6 ]
1
6 I n: i4 l' E: A3 O+ Q2
2 W: ^) R2 T; f# p: g9 }+ w8 S( F9 {0 b3
! z# }6 T* ?5 q8 n/ A0 c4
) g2 c* x, F# N) T" A這類函數 通常是不可以有函數參數的 (比如篩質數函數), 也就是 她的參數 是根據題目的最大數據範圍 而不是錄入的值;5 h- _: f* S7 k# U+ F# _) t" Y+ ^; v
( S a; ~0 w8 H4 S9 ~- i
不要用__attribute__((constructor)), 她是報錯的, 因為他不是在運行時執行的, 而我們的需求是在運行時執行;
! z) K& R) H: s6 I6 t
: d3 l, R) X Y- S0 x& q@DELI;
. @& B' j+ S i2 I
{( J( U. x5 O#類/命名空間的Debug調試#6 _* N, \# \# v. u! Q! e$ A7 y
- V! n# q% z+ o
class ___X{: R+ ~# Z" B; m' P8 u' x- B; ?
friend ostream& operator<<( ostream & _cout, const ___X & _a){
" ]5 \' [+ I9 @- R0 I _cout<<"\n"; ! M* u) T! P1 U, K( Q& d f
DE_( "___X-Debug-Begin");$ m& r, s! J8 L. ^1 D* u5 W' s
( q! l2 ^- W$ H& y e cout<< ?; // 此時不可以使用`DE_(?) 或 `Debug::__CoutItems(?)`, 必須使用原生的`cout`;% g6 o6 O T+ F
' m& \, G8 p: c* a! |" e
DE_( "___X-Debug-End");$ @9 j8 H# U& i$ M p& z- M+ B
}
1 e% B' ]" a( j# P/ B- r}
+ ~, X ?7 W7 F1 X
: L0 d, m( N. ^2 S* J/ Q* |namespace ___X{6 b2 P/ q3 x! d7 v
void Debug(){0 k5 Y+ s5 l8 u3 [) ?# ?
DE_( "___X-Debug-Begin");
8 }7 u& C9 a& B1 _
/ X* w2 r. H! |5 [( H q cout<< ?; // 此時不可以使用`DE_(?) 或 `Debug::__CoutItems(?)`, 必須使用原生的`cout`;
( c1 { G( \4 D# P- i0 a. L1 X/ L# p" u
DE_( "___X-Debug-End");
' _8 ?, a6 T3 ~. }0 s) g6 ? R6 L }
8 _6 @9 d, x1 L" @6 l2 K/ T7 F: P9 ~}0 F# n4 g* y( |# N6 R& o {
& q7 N3 V$ B& C( E. {2 Y
@DELI;* @7 S6 t2 g; M- S
" Q! z N, P! x. D8 a
#嵌入模板的全局变量#
2 q9 k5 R: G! W& n" ^; M: J
1 ~! \4 d7 L( F% |/ ^{ // ___XX
4 |, {7 P# K1 Z' l const int ___Number = ?; // 这里就叫做全局变量; 要以三个`___`开头7 N8 w* b% e1 a1 o
int ___N = ?;5 D# R# x; _/ X+ P
for( int i = 1; i <= 5; ++i){/ B9 U: x2 I: x0 H, X! m
int a = ?; // 像`i,a`这种*临时变量* 可以不用写`___`开头;& }8 |: g7 n* E& x; O& L7 t6 ~
}6 @8 S5 I0 r8 F0 A2 x u0 A
% C/ u" d, Z* x1 l( C4 l) L} // ___XX& X5 U1 L- E. P- @5 k
5 g8 G/ ~! B6 W! `+ w@DELI;
1 a9 Q9 O: L' E5 Z+ a( Y. }$ t, ?6 X1 t( A" ~# K! m, A% @
#Initialize函数, 强制的放到构造函数里#! D3 e H: |6 j6 ^0 n2 E. f% ~9 X
最经典的例子是(建图)) N2 {& S/ H8 [4 O& T$ ]+ _5 X
, m7 M5 u6 d" m8 k& c0 RGraph( int _points_count_maximum, int _edges_count_maximum){}
( r1 P# L- T; d. T* n0 bvoid Initialize( int _points_count){}$ c# h& W# p% q$ C
1
4 X3 U6 A% p) }; q& }3 y0 `20 g4 J# t, `: L, u4 p- }4 [5 Q2 Y7 Z7 C
这样分来 会导致, 每次使用时 必须是: Graph G( 100005, 200005); G.Initialize( n), 也就是两个代码行 (两个操作, 两个步骤)0 a( p8 A5 |/ c( [6 @4 G' `
一旦忘记手动的调用Initialize函数, 虽然会报警, 那你还需要再去写代码 补上调用这个函数;
' G, `$ i4 k, K) m, Y: v6 \6 R
8 R2 g& t8 U" B- \! k- f7 V: v当我们将Initialize函数, 嵌入到 构造函数 里& e; Y s* S4 b$ ~: |
6 ?/ Q" R0 g- x# r% K6 }Graph( int _points_count_maximum, int _edges_count_maximum, int _points_count){0 p8 i2 K. ~3 e u; \2 G
...2 _2 w6 } a Y# | C8 |; ]& P
//--
- _3 j) `. @& s; S& v$ H+ y2 F Initialize( _points_count);3 U5 ?1 h- L5 [: N& y& \
}
0 u6 Q4 a8 ^2 ^9 n; h" S6 mvoid Initialize( int _points_count){}
& p8 T! ]" a" F' H* c2 {
: X7 H6 g; ^+ w$ J8 t! m X0 u注意, Initialize函数和原来是一样的, 只是做了两个事情:
/ c' U8 X/ b8 X' ~' O/ h0 D1 将Initialize函数的参数 接到构造函数参数的后面 (比如, 原来构造函数参数是a,b,c, Initialize函数参数是x,y,z, 那么现在变成构造函数参数变成了a,b,c, x,y,z); y# y9 q3 n8 V7 I: A" F5 B5 E
2 在构造函数的最最结尾, 调用Initialize( x, y, z)函数;+ Y8 a, S+ k4 ]) }/ s
% m. L1 W7 _8 r9 q
@DELI;" w) ~9 ~! s4 z* |, b7 o
' B) e- [7 J* s8 v3 f
#数组长度用函数传参来指定#/ d1 g8 `4 s1 I/ i L7 a- K
* k3 r7 _0 O4 z4 K
template< int _Maximum>
5 b# z: j- n: O, Z$ Aclass ST{: j/ ^, P5 M( w+ J' g3 ~$ s
ST(){8 |$ d: Y- p/ r7 ]5 G: H/ B4 e0 `
array = new int[ _Maximum];0 V4 L& h- M8 k% r' _. _2 X5 J) b3 ~
}3 F2 R! y% j; v2 p+ F
private:) V! R* b8 C0 M B' S" u5 v
int * array;# G# e* d9 e2 N- ~/ O( x
};4 X; v7 B5 o2 p
* `: X2 B# G8 v4 o/ A& n; g
The above code should be replaced to:
" h# `2 w1 F6 T; ^( k- N- C4 a. I$ }' G# g% x
class ST{
H1 B: D% y* S ST( int _maximum)
2 ]# e- }3 Z o$ V5 w5 ?! J. o0 f! e :
0 A0 u- J9 ~4 s, i+ x# q maximum( _maximum){
, N% B1 e w4 r4 B array = new int[ maximum];" L$ V, b9 _1 |+ ~5 J
}+ ^ F" C: l$ q: v- T
private:
, w+ q+ u) n0 E3 @ x int * array;
# W5 \- _9 c2 u. D) ^5 U2 k( l. \6 A6 E const int maximum;
& h% d) |3 v% ?};" Q. X! C) D! {( c
' q i# _& s; G@DELI;& u; l- h4 Y' s$ G/ I! r
笔记
( N1 w+ S i- F# p: c有向无环图DAG
: h$ I; V# \) x/ r! c最小路径点覆盖
6 p. k& I& U; X* I# f% x8 o. s# q//{ @Snippet, `ZuiXiao LuJing DianFuGai (最小路径点覆盖)`
! _3 _' K2 @/ n# g& T% D{
}* @! c/ L( t int n = `the points-range in the DAG`;
6 ?# x2 z' K& k( z/ Y+ B7 _& N/ \; d //--3 f( d9 P, k3 `% A+ A9 L
BipartiteGraph B( n * 2, `the edges-count in the DAG`);0 g ^6 J; {) ?8 r. k" F5 M
B.Initialize( n * 2);
w" Y: |: K5 T. S# @& s7 b6 ? for( int i = 0; i < n * 2; ++i){% v" ^/ o1 i/ m/ p4 ]
if( i < n) B.Set_pointBelongingness( i, true);
( e4 [3 a( I r4 L p7 ? else B.Set_pointBelongingness( i, false);
7 d! M3 q1 Z- A8 K0 A* o0 Y }" q: h& a" B7 T: [+ r
for( `s -> t` : all edges in the `DAG`){2 s# F" y2 w! F7 m8 K
B.Add_edge( s, t, 0);
8 ?5 k* k6 ]# F$ {! [ ? }
- e+ [+ r( q4 s1 f" Q8 l/ Z; Y) O# D //--
6 `4 m$ K' T7 Q! H- S Bipartite_MaximalMatch M( &B);5 S6 x/ W# H( @' }5 U7 S
M.Initialize();
5 P X$ ], e& A6 Z# R! c $(n - M.Get_maxMatch()) is the answer;
$ d/ b. {1 K2 a; c3 F}( O9 g) I/ F7 W/ i
//} @Snippet, `ZuiXiao LuJing DianFuGai (最小路径点覆盖)`# V/ x/ L. ~$ Y, A3 |3 l2 w9 H8 j
F+ }6 Y4 ^, s
最小路径重复点覆盖, 最大路径独立集
5 Y: |3 r1 ]" P; w+ Q//{ @Snippet, `ZuiXiao LuJing ChongFu DianFuGai (最小路径重复点覆盖)` `ZuiDa LuJing DuLiJi (最大路径独立集)`, S9 ?! m, @( [9 F+ z' g
{
3 `& B8 R" W$ U5 N) n5 Z4 u int n = `the points-range in the DAG`;
/ e4 `( k# u3 c/ h8 f9 c bool * edges[ @PlaceHolder] = $(edges[a][b] means a edge `a->b` in the DAG`;; G) d* T7 J' l9 Y. ] T8 B
//--
; c: B; v4 }# [ $(perform the `Floyd-Boolean` on @Var(edges));
9 W. \# q% [) ]" ? //--
+ q3 Z3 a$ h# E' k0 }% a- ` BipartiteGraph B( n * 2, n * n);
2 ~ z" i4 |/ u; h B.Initialize( n * 2);
" k8 ]" ~0 B8 d+ @! K# c! @9 u% ] for( int i = 0; i < n * 2; ++i){6 K( x* J/ T* J& D# ^+ G' C# z
if( i < n) B.Set_pointBelongingness( i, true);
6 v( z* a' A3 [6 Z( q. G0 n else B.Set_pointBelongingness( i, false);: A$ h ~2 i* u) ]: v
}; w7 J& I" {' m. u" Z& l& N
for( int a = 0; a < n; ++a){
# `3 s6 v" V; P3 N# V9 o9 d) h for( int b = 0; b < n; ++b){" }! I0 n+ l S; |
if( false == edges[ a][ b]){ continue;}+ ]0 v; W. j2 T
B.Add_edge( a, b + n);, m/ k6 [, \1 B8 F" w
}
$ ]1 o- S* N4 @, P }0 r) ]. L6 {5 o$ @1 ]. o
//--
: o2 t- D& S. n6 F; L4 `0 c Bipartite_MaximalMatch M( &B);
: v7 F% T. t/ _ M.Initialize();# u+ R+ w' o# v6 k6 H6 d
$(n - M.Get_maxMatch()) is the answer;% M3 \$ \2 p* A9 d: o# Z
}- w9 m! U# I$ [1 M
//} @Snippet, `ZuiXiao LuJing ChongFu DianFuGai (最小路径重复点覆盖)` `ZuiDa LuJing DuLiJi (最大路径独立集)`0 V' ?1 u( u `) ^" h; q( L# L
7 D0 o. }% c: \& I1 }4 I. F* E
DAG的终点
|9 \9 I1 F9 H9 W//{ @Snippet, `EndPoints of a DAG`
9 [3 p% ^/ k) F8 A$ C( N4 u) ^{8 W: v5 [: r! ^8 T F, b. A0 e
int n = `the points-range of the DAG`;/ ?% u) ?9 \3 G; p5 z5 _/ l; y
int * departure = `int ?[ >= n]`; //< the departure-degree of a point;
* ^& d, E# T: K- S2 W# X* z! r memset( departure, 0, sizeof( int) * n);& D( R, j i) f E- ]4 O7 t$ I' p
for( `a -> b` : $(all edges in the DAG)){
- T/ k2 |1 h5 F ++ departure[ a];+ l1 v2 s; R; \
}! P' y+ N) ^/ i
for( int i = 0; i < n; ++i){
$ ^6 |8 p' U3 b0 ^6 u" Y if( departure[ i] == 0){
6 u% n7 e9 l1 }8 P& L; A//< `i` is a End-Point in DAG
" @4 N2 x# }, K; n7 S* X9 q }, `6 w3 G- g, @. n1 V
}( R+ O9 L1 Y5 p( n5 O; \
}
" g" S0 _( e' B! c6 d6 }4 r//} @Snippet, `EndPoints of a DAG`- H" }5 U. B8 e) M+ N* S( d8 }. D& B0 T
" {" U% c: i. ~( mDAG的起点* |2 {9 {& j% V- i% b
//{ @Snippet, `StartPoints of a DAG`7 a4 K; a9 V* v- u$ v2 o
{
; q* f. c3 ]& _9 }, k, g+ O int n = `the points-range of the DAG`;
# y5 S! P4 }: N+ g( j int * incidence = `int ?[ >= n]`; //< the incidence-degree of a point;
+ h& M; q+ \' _: H3 N6 Y9 s4 }8 J3 p memset( incidence, 0, sizeof( int) * n);
( r" J% D7 y( A0 Z0 y: o for( `a -> b` : $(all edges in the DAG)){' F+ R- z4 Q: A; c
++ incidence[ b];
) L8 T& W- l f }
0 G1 z- W' C3 B2 H for( int i = 0; i < n; ++i){
) t/ y' j/ C' ] b. Z' q- ]" T if( incidence[ i] == 0){4 H4 D3 Q& B1 N! P
//< `i` is a Start-Point in DAG& P, e/ V( M4 t. I! h
}8 S a8 J% f+ j7 J) P" M
}
$ a3 E! |5 h3 V/ ~9 V8 W' ^% e0 L}5 j: k) u2 D# G
//} @Snippet, `StartPoints of a DAG`
' ]' z) y5 p5 m4 d5 y$ H# C# f6 J, ]! d1 o
判断一个图是否为DAG, 求拓扑序3 t. `( l1 ^- r/ a7 F
bool Work(){
0 E# J' B9 H: |( G. |2 a) R+ @. h1 ?//< `1` Check whether a Graph is a DAG; `2` Get TopologySequence;+ u- J5 c' R( b% ]) l6 Z3 E
int points_range = @Unfinished;: b9 @9 a+ l/ p
int * topological_sequence = @Unfinished(an outside array whose length must `>=` @Var(points_range));
1 E+ w6 T; }$ E int * incidence = @Unfinished(an outside array whose length must `>=` @Var(points_range));* L6 P* k: N5 \; R
memset( incidence, 0, sizeof( int) * points_range);4 w1 V/ w7 S3 x) l+ a2 o6 w
for( `a -> b` : $(all edges in the DAG){0 H7 z- h' O6 Y9 \" y" J& c
++ incidence[ b];
2 m6 {- _. ]- |- J T }( Q" \! z6 p8 m2 u' E
int size = 0;4 R6 J1 a. f: ~8 b9 Z) ^, L7 N
for( int s = 0; s < points_range; ++s){
- F/ y& d& G3 m! M5 ^- G if( incidence[ s] == 0){
# [- ]* a: n' z- t2 Q# C3 z, [6 w topological_sequence[ size] = s;3 ?" @6 U& v/ w! Z) a
++ size;2 u8 Z. m5 Y6 q N. z @
}
* f$ i5 Q7 u! v }5 ]: ~! i5 `5 f8 L- w
int head = 0;
) ^4 K. ~+ t2 r: j# d& n while( head < size){
% U# z4 K& e" H D6 z. L3 Q int cur = topological_sequence[ head];6 u+ j( {* I; d8 j+ z" h5 n% C( e
++ head;/ m; A8 c1 r' j0 I6 Q
for( `a` : $(all adjacent-points of `cur`){- q# c( P! @# a
-- incidence[ a];
6 x! k9 H$ @* [/ k if( incidence[ a] == 0){# J: W+ |9 u' k0 [; T L
topological_sequence[ size ++] = a;
+ {) ?; A+ r8 M }
8 M: n( i8 F) f* O+ m6 u }2 l" ~0 O; a( L8 ^/ M/ H
}
U- ?5 x' [9 _" I& L4 z7 c. a if( size != points_range){
7 C( O% n. ?4 Y$ B! E; @" e return false;
$ y0 `$ d. K% ]2 r M }9 B8 h$ [ j7 n- i( A
//>< The answer Topological-Sequence has been stored in @Var(topological_sequence)# T! _) Y1 ^( U6 h, n% _' a
return true;) d, @' M8 c/ X" ~
} k `4 U/ m( r: s% w' C: h
% S( \* H1 ~+ L( y* V3 ?图论( U& e* c6 m3 R5 o; m9 |3 Z7 q
最短路
; C- Z6 ~# n, f" s4 L0 T; j6 l% rTARJAN
. k1 P( s5 ^* @/ N2 T& m% `无向图-PBCC点双连通分量
8 U8 P) t A9 ^ I) q" Z Z+ 割点
7 y* w* z; _ d& {4 h$ l" G
* x% N3 F3 J* v6 Q5 x//{ Tarjan_PBCC-Declaration
8 H# Z+ M1 J& N+ Q `0 I9 ?# itemplate< class _Edge_Type>! F. ]! N. b4 H- R/ X0 E5 H- b
class Tarjan_PBCC{( H9 Q# g O0 t. `
public:
# ~$ n" g- x5 H& G7 D/ u& p* H2 w const vector< int> * Pbcc;
! [' @" @. {2 q3 ?; S9 V const bool * Is_cutPoint;* U+ s7 `$ K5 O4 C! C2 E: r( R/ I
//-- variable ends
' Z: M/ P/ W A' _* U, D1 u Tarjan_PBCC( const Graph< _Edge_Type> *);: m% O6 g: k. p# W
void Initialize();
# B2 ]( p; r% {2 u( J w% i: G+ R; [% ? int Get_pbcc_count() const;! E6 V+ h( v3 M. `. I
private:
! y5 M. Q a% p5 o const Graph< _Edge_Type> * graph;
c7 y) R2 F3 K, o int * stack_;
$ w/ R! f6 k2 z, y8 W4 Z int stack_top;
2 f6 K$ D$ G3 U7 x int * dfs_id;5 m; k: L' F' \" T' e
int dfs_idCounter;/ Z# o4 {$ ~' B# a- v5 \ N
int * low_id;
, r3 g N$ N) H8 a% ~2 g* ? vector< int> * pbcc;
; E7 m* J/ d4 F0 x$ h int pbcc_count;7 G- \1 L+ {. q0 O. B# |
int dfs_startPoint;
7 R7 W9 r) b1 y# {8 R' e9 [4 g; O# I bool * is_cutPoint;
+ C4 H/ l* e b1 d& h. k" ~ int cutPoint_count;4 l! I: a# N9 A5 D% Q- O6 \# ?
//-- variable ends
0 z& k" i8 M; f6 P& X void dfs( int);$ d \. K* N$ t) b
};' ?& R; Q9 H* |5 Y& b) b0 G+ x
//} Tarjan_PBCC-Declaration5 y, y3 o* k9 {1 a3 p( M
& B$ h Y* c4 G2 B1 \4 J% M2 z
//{ Tarjan_PBCC-Implementation, o* Q! F& M# B( e3 }9 n
//{ Variable-Annotation0 J; g+ Z, x8 w" B u
//{ @Var(pbcc)
. r" b) _. b0 a# e6 K; d) b$ H( f // + `pbcc[i]={a1,a2,...}` means that the PBCC with id `i` consists of these points {a1,a2,...}
! c8 H# h% O! T6 h& f+ [" k2 c //} @Var(pbcc)2 j& c( h) }! Z8 s- q9 ~
//{ @Var(graph)+ Z* p/ T9 L2 A. \1 R" t
// + must be a undirected-graph, i.e., Edge[i] = Edge[i^1]+ I; C5 j5 Q# F2 j+ N# {
//} @Var(graph)0 a9 T$ X+ m5 M9 x# M
//} Variable-Annotation( o7 R/ [# E3 a) ~* y( K) q
template< class _Edge_Type> int Tarjan_PBCC< _Edge_Type>::Get_cutPoint_count() const{ return cutPoint_count;}
' [) [/ a6 B4 t, ?' h4 W* e. btemplate< class _Edge_Type> int Tarjan_PBCC< _Edge_Type>::Get_pbcc_count() const{ return pbcc_count;}
: R% x. c: b$ h' A9 _) vtemplate< class _Edge_Type> Tarjan_PBCC< _Edge_Type>::Tarjan_PBCC( const Graph< _Edge_Type> * _graph)6 `: ~* G% a7 j0 U
:
. n4 t3 O, h9 N+ S* ^, z: C+ w graph( _graph){
4 g3 P5 [: Z% D% L; Q stack_ = new int[ graph->Get_pointsCountMaximum()];
" U8 r7 c, H8 P. q: O9 f2 J dfs_id = new int[ graph->Get_pointsCountMaximum()];. Z% a. w( x' t. w
low_id = new int[ graph->Get_pointsCountMaximum()];/ {4 y# |2 E2 n: R; r! X% t# M
pbcc = new vector< int>[ graph->Get_pointsCountMaximum()];1 D8 D& L: X5 J& B
is_cutPoint = new bool[ graph->Get_pointsCountMaximum()];+ o4 H2 X% f4 }
//--/ M2 O, n2 _$ W9 E1 _, H6 T ?
Pbcc = pbcc;. A/ s% w! r$ d
Is_cutPoint = is_cutPoint;; Z: V5 ]# Y' n7 i( x- S H' f
}
: J B1 d! [" O' j8 q$ e3 t* _template< class _Edge_Type> void Tarjan_PBCC< _Edge_Type>::Initialize(){
% i0 P/ [- j5 L) \' u stack_top = 0;
; r0 j; D/ t* ^ g c; T3 T; \ dfs_idCounter = 0;
; A- ]! \7 A* a" N6 v pbcc_count = 0;8 a8 F! ^3 {# j
cutPoint_count = 0;
6 h+ F6 i4 n1 o- v0 y for( int i = 0; i < graph->Get_pointsCount(); ++i){ pbcc[ i].clear();}
) ]6 N( e7 F { memset( is_cutPoint, false, sizeof( bool) * graph->Get_pointsCount());8 u6 @; E! ^( Q
memset( dfs_id, -1, sizeof( int) * graph->Get_pointsCount());
; r5 P9 }; e: F6 w* ~6 R1 F for( int i = 0; i < graph->Get_pointsCount(); ++i){
+ k8 D3 S/ v6 ~, K1 _ if( -1 == dfs_id[ i]){
' Z; K0 ~8 S/ h( @! { dfs_startPoint = i;
/ m- B# F* v* k g- _0 i dfs( i);3 X9 ]3 Z0 v& O# Q1 f
}
0 T/ z/ }+ R( G7 B' W1 k }
$ p, }4 D3 [1 i& O1 p( f4 x}
4 n; }$ Z9 t/ M, Otemplate< class _Edge_Type> void Tarjan_PBCC< _Edge_Type>::dfs( int _cur){
0 G5 c- W% K% j* [ stack_[ stack_top ++] = _cur;' E- Q7 [; j9 X. \0 E8 W& _
low_id[ _cur] = dfs_id[ _cur] = dfs_idCounter ++;+ z. i, o- J5 A% Y7 J7 W
//--2 P. M8 S- W6 w- A
int cc_count = 0;: ]5 [1 l$ x# g- t) E
if( _cur != dfs_startPoint){ ++ cc_count;}3 K+ }9 q \/ S. L$ ]4 E$ j! p
for( int nex, edge = graph->Head[ _cur]; ~edge; edge = graph->Next[ edge]){5 R9 e' p6 \, X i# k0 r
nex = graph->Vertex[ edge];' c; |7 p* p& ]& N( d& E
if( -1 == dfs_id[ nex]){
{* U: s& E8 x8 t8 e- _. V dfs( nex);1 v# z/ B& ~$ C% c
//>< `low_id[nex]` always `<= dfs_id[_cur]`
9 }& M m/ P1 l" ]8 ` if( low_id[ nex] == dfs_id[ _cur]){
) f1 j* H0 F, C. ^3 a8 K ++ cc_count;4 H6 W6 W1 o! Q+ [- G* Q* {
if( cc_count >= 2){
! Y' U, X$ \! }! J: L is_cutPoint[ _cur] = true;% R8 {9 w3 `9 C3 q, Q
++ cutPoint_count;
' F- L6 M/ t" d. g5 |: { while( true){
, g$ S: Z' `- Y! h+ k2 n/ |! r int c = stack_[ stack_top - 1];
5 f" \ ?, ^3 n/ m7 l0 V% I/ D -- stack_top;
: U8 x. q; l. o v( ` 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.6 {1 R/ ~9 x' y- c# }, i
if( c == nex){ break;}
! Z' o1 y7 X6 J9 A }( Y( G! G+ f1 [( W
pbcc[ pbcc_count].push_back( _cur);
. I4 B+ ^0 k+ ^/ [; x& A //>< `pbcc[ pbcc_count].size()` >= 2
; s, s W7 p4 _" @1 N6 f6 B6 @ ++ pbcc_count;
: V& a& m F2 _! `' R7 M }
& b; i- E! Q B4 @- Q7 B }1 p- M1 O0 }) F* {
low_id[ _cur] = min( low_id[ nex], low_id[ _cur]);
# ?6 @; k% ^4 \& T }
1 o& r- T) o- R else{ //< `nex` must on the `stack` due to the graph is Undirected C3 ^; O* M9 F" E
low_id[ _cur] = min( dfs_id[ nex], low_id[ _cur]);; \4 W* y% R& {, J: w) B. [
}
; u8 M3 L+ B, n5 P5 u0 X0 S }7 l, ?3 @0 G# F6 N. _' m/ c2 O) D; ^
//--
" I0 M; \% \; O* b) ]3 b if( _cur == dfs_startPoint){3 r( f: x! @" s- [6 ~
while( true){ z& V0 M2 U+ E* H4 K7 \+ h* W
int c = stack_[ stack_top - 1];
' {7 v/ o3 T, T+ [6 h -- stack_top;
# {1 ]! f* N$ s( z* ~* {5 v5 f1 t& g pbcc[ pbcc_count].push_back( c);3 w5 q" D3 W# c# M
if( c == _cur){ break;}
2 T4 p& {: t; n- x }2 a3 `$ U+ F0 M! X8 ?
++ pbcc_count;
% k Q& L b: `. M6 R }
3 `% i7 y8 ?( H$ r- V, e //>< `cc_count` means the number of Connected-Component when `_cur` was removed from the current Connected-Component (whatever `cur` is Cut-Point or not);
2 s1 V) r* v2 N) {1 i) }" w}
# r5 V) t8 N; _6 U//} Tarjan_PBCC-Implementation
4 `$ _4 K& c) @
7 G* R. g. w8 t/ }. o无向图-EBCC边双连通分量
' {6 }% I/ I$ E4 E3 d! C/ \+ 桥6 R/ _ f1 {3 Z \0 l
' I7 c8 S. @; Y2 S//{ Tarjan_EBCC-Declaration
j5 a$ e) E5 S6 E6 etemplate< class _Edge_Type>
/ i$ Y4 C( H4 K1 b& y2 |class Tarjan_EBCC{/ a& t9 Y# X" R: E0 V
public:
( l2 |: r4 G" P1 A const int * Ebcc_id;
8 x# Y$ W9 |3 q( L const int * Ebcc_size;5 m3 i; x5 w& V5 j% B* ?4 E+ ~
//-- variable ends5 W4 C' [" O1 d. f
Tarjan_EBCC( const Graph< _Edge_Type> *);, _0 l0 } r' m
void Initialize();/ q( V/ r1 W. `8 i* B
int Get_ebcc_count() const;/ j- H/ g0 y# `0 a' y5 I
const Graph< _Edge_Type> * Build_tree() const;% M9 i3 O0 ^: T0 f- W* K& x
private:
" S$ P A, m5 e( N$ S% A const Graph< _Edge_Type> * graph;
7 b) |6 [; S- I9 [$ \. Z int * stack_;
+ [; ~' l! w# X" h# T6 M int stack_top;1 J ?; [$ ?4 x. X6 c$ `: p
int * dfs_id;
: {! {( U6 K& X! T1 {; z int * low_id;
, E$ N" J$ O9 m! O, H int dfs_idCounter;; o! \1 l. A5 }3 i
int * ebcc_id;
! e( |5 _1 I$ V8 X7 ~5 l int * ebcc_size;3 ~. ]0 [. W* r7 T
int ebcc_count;2 ^" J) ]. r# S$ A$ F. v* i! _) J
//-- variable ends
1 s" j# [, T8 F9 K/ ^ void dfs( int, int);
) t$ e# j) Y C+ T; Y! ]};
/ k# v) o! s# x1 t5 U3 L6 [//} Tarjan_EBCC-Declaration
8 V. Y2 [' z' } R3 E- ]2 S# l- E2 T4 t( t# y2 m
//{ Tarjan_EBCC-Implementation# d3 c. D" ^: E" {
//{ Variable-Annotation8 ^5 N4 U' f. c6 E$ y
//{ @Var(graph): t6 D; c+ l4 F1 N/ ?! ]
// + must be a undirected-graph, i.e., Edge[i] = Edge[i^1]
" s7 z# I) e+ v8 Y0 G1 M" ^; B //} @Var(graph)
1 i! U/ A$ K# }& U, W //{ @Var(Ebcc_id)3 N" c2 K, t+ [8 U
// + `y=Ebcc_id[x]` where `x` is a point of @Var(ptrRef_graph) and `y` belongs to `[0, @Func(Get_ebcc_count)-1]`# D/ W8 |0 a4 q: |5 o0 q7 x, b3 _
//} @Var(Ebcc_id)4 s! |% f* r- ~, k9 h
//{ @Var(Ebcc_size)" }: P- ^7 L$ R3 T7 `4 v
// + `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)
' R- X- }6 y7 b) X //} @Var(Ebcc_size)
& X1 D% T! V+ w& T! T' Y6 d& r //} Variable-Annotation
" F3 l9 i) L1 _' ]template< class _Edge_Type> Tarjan_EBCC< _Edge_Type>::Tarjan_EBCC( const Graph< _Edge_Type> * _graph); ~6 ^/ D9 m+ ~0 M
:
1 V6 @- N! m( f% H& p: r graph( _graph){3 u) G4 w L9 a& i
stack_ = new int[ graph->Get_pointsCountMaximum()];6 J! x3 u" j- @. a
ebcc_id = new int[ graph->Get_pointsCountMaximum()];' x$ o" Z& f p Y) i6 R& Y6 z
ebcc_size = new int[ graph->Get_pointsCountMaximum()];& H e7 q/ \, V4 K9 S
dfs_id = new int[ graph->Get_pointsCountMaximum()];( e0 d' t! c9 e4 x l
low_id = new int[ graph->Get_pointsCountMaximum()];
0 C: E: h: m+ z/ ?2 y" h+ t1 K* { //--& l( ?% g; p0 a6 l
Ebcc_id = ebcc_id;8 U+ C! }$ Z, H, `6 A
Ebcc_size = ebcc_size;
* M( k7 J( k8 T4 [8 Z}* }" t" p; }/ N5 |7 P3 z) J
template< class _Edge_Type> void Tarjan_EBCC< _Edge_Type>::Initialize(){1 ]# M: J7 \! {9 }; J" S
stack_top = 0;* D( H: |4 b/ X o- G* _
dfs_idCounter= 0;& F; `- d" Q: h0 t. v2 t. w
ebcc_count = 0;
/ o5 k. R0 w& W" K4 \- P memset( dfs_id, -1, sizeof( int) * graph->Get_pointsCount());% d9 }( r* }) O, e' [
for( int i = 0; i < graph->Get_pointsCount(); ++i){
8 {( e! |( j/ z% P- `% G& @ if( -1 == dfs_id[ i]){
; D0 l L4 y& ? dfs( i, -1);
/ W' s/ ?' q; j% O% g4 k' e& W }
/ \9 l4 a' ]8 H* @ }( S7 J! O4 s T, C- p4 V: e9 \) y$ O
}
. Z+ v6 G6 h9 r( K) Qtemplate< class _Edge_Type> const Graph< _Edge_Type> * Tarjan_EBCC< _Edge_Type>::Build_tree() const{, h3 W( L3 W ]- F- F. b
//< + Make sure @Func(Initialize) has been called
) G2 i; d3 }# r& L" K; }- c//< + There is at most one undirected-edge between any two points in the Tree (i.e., @Ret)
% k8 r% U5 h$ d H6 y* p, q Graph< _Edge_Type> * Tree = new Graph< _Edge_Type>( ebcc_count, graph->Get_edgesCountMaximum());
. }+ @% m& n+ Y) Z% L Tree->Initialize( ebcc_count);
& t# p- p0 M' a3 E+ q' i3 j for( int a, b, i = 0; i < graph->Get_pointsCount(); ++i){% V7 Z( h' T5 B" x, {: |% M. C
for( int j, z = graph->Head[ i]; ~z; z = graph->Next[ z]){
+ W3 A! R; m* ^2 e/ D& L( S j = graph->Vertex[ z];# w5 z! k( b, t. `3 A: S( w
a = ebcc_id[ i];
+ Z7 O3 i) m$ H, I, [ b = ebcc_id[ j];
: v- ^. R, J% U( \! z1 J if( a != b){4 g4 h8 Y Y6 Q5 S; s9 Z
// Now, there must has no edges between `ebcc_id[ i]` and `ebcc_id[ j]`' }1 ^% Z) n- B- V
Tree->Add_edge( ebcc_id[ i], ebcc_id[ j], graph->Weight[ z]);
- f0 n' D/ k9 B8 E, @" E8 z }2 X3 h( y# Y f0 ^7 O; ?( C: T& W
}5 J* f% C: L# g8 M; s6 e9 p
}: I* Q; H7 h5 ?) X2 n1 k
return Tree;9 S0 i& M2 G% T/ T
}
% Y, }" X" j" f jtemplate< class _Edge_Type> void Tarjan_EBCC< _Edge_Type>::dfs( int _cur, int _father_edgeId){
0 A1 d& V7 d: m% f5 p8 _2 W P stack_[ stack_top ++] = _cur;
+ S3 B' j6 ^) u" t low_id[ _cur] = dfs_id[ _cur] = dfs_idCounter ++;
) T# _3 R1 n4 N* c //--8 G. B8 C0 {* X- J) Q( `' S
for( int nex, edge = graph->Head[ _cur]; ~edge; edge = graph->Next[ edge]){4 x& w0 T$ t V" p% g) B
nex = graph->Vertex[ edge];8 j+ \+ T, j9 W4 h m. J
if( (edge ^ 1) == _father_edgeId){ continue;}
5 k- _; D* j; P0 S+ m if( -1 == dfs_id[ nex]){
+ N6 |$ V# R, A dfs( nex, edge);# z; J# K5 p5 C9 o* B
low_id[ _cur] = min( low_id[ nex], low_id[ _cur]);
% M$ B) B* ?1 K2 Y+ H6 a V }
. `5 N! ]5 }' L& t else{
7 @6 w1 N: V+ z8 W2 y' n ]/ S low_id[ _cur] = min( dfs_id[ nex], low_id[ _cur]);
+ _+ Z, ^ o3 Z: L }! @1 T) V) Q8 b: w7 E" T0 D
}: P0 c: q- Q- Q2 X8 c9 A) h; n A2 L
if( low_id[ _cur] == dfs_id[ _cur]){. G, s* U7 M' r3 f% ]5 {
ebcc_size[ ebcc_count] = 0;; O4 o; S& ?$ U$ _, }
while( true){# s6 c( U8 W( i) f/ z4 D
int c = stack_[ stack_top - 1];
/ f8 j$ C6 n' I2 g: p: _0 x -- stack_top;
: b' c# I; ~# E' W$ a ebcc_id[ c] = ebcc_count;) f. \5 [: W K# m" E1 \
++ ebcc_size[ ebcc_count];! c" w6 b, u/ K' V- m
if( c == _cur){ break;}: d0 _+ N3 c/ O) ]7 E/ x
}* {& U" r$ y9 \
++ ebcc_count;
# p1 Q, M* w/ x7 ~) {- _ }
6 I2 Q1 [; J- p( E% `6 c* H}9 ?# Y. ?; n3 v5 i" ]4 b
//} Tarjan_EBCC-Implementation
) H2 {0 P' V5 j. U, l" W6 r1 M+ ?$ V/ K! p: O) p
SCC有向图强联通分量
9 ^. n! j* U5 z0 m' q- Q//{ Tarjan_SCC: K! A, q+ O {& O% g9 u
template< class _Weight_Type>3 p* J7 Z+ O$ M$ J
class Tarjan_SCC{' [8 f0 f% U3 g% ]" B
public:
6 e9 ?2 x9 [. }) v# Q const int * Scc_id;' q& i/ B+ t. A7 e( Y, {, N2 e
const int * Scc_size;
& a/ |& |! M% \- W' } //-- variable ends2 Y) B. y0 _5 O( Z% K. e
Tarjan_SCC( const Graph< _Weight_Type> *);0 A4 }4 m1 C4 L; B8 x# N# ?% V
void Initialize();3 X, E; d5 Y3 v2 N$ m. `' e& e9 D
int Get_scc_count() const;
' b1 b) g# C8 m" N: ]5 ]9 b- D const Graph< _Weight_Type> * Build_DAG() const;
8 w% N6 f# O: m. L4 i& u+ ^ const Graph< _Weight_Type> * Build_DAG_uniqueEdges() const;' p5 P6 w1 r, c5 }, y
private:
8 e4 I- b, j' x* z const Graph< _Weight_Type> * ptrRef_graph;3 J y/ v* W4 H; L% P% X
int * ptrNew_queue;
- v7 s3 {) d( Z6 T) v# g/ R0 M: [ int queue_tail;
4 G" M/ o2 H P: M' L; Q bool * ptrNew_isInQueue;
% D9 G. m6 t7 E6 v8 Y! F1 X( h int dfsOrderId_counter;/ H4 t+ y( Q3 J3 N$ L" y
int * ptrNew_sccId;
7 C2 ~* j* ]( d* u1 H: K int scc_id_counter;
! [: t6 R$ @# {5 c) ? int * ptrNew_sccSize;
1 ~. u$ i7 y) R# C9 W9 w //-- variable ends
$ X$ U7 Y" F( K3 R' O0 n! I% ] n& o9 d void dfs( int);
. h# U) v. V0 L! h% B/ G};
' N# w; _/ V( u: A2 i# Z6 o//{ Variable-Annotation& A! ^# h) y; r) v6 F
// + @Var(Scc_id)
$ J/ s z) u9 w- B2 @// . `y=Scc_id[x]` where `x` is a point of @Var(ptrRef_graph) and `y` belongs to `[0, @Func(Get_scc_count)-1]`8 l- C+ S! r0 ^+ _6 Z6 t; m9 a
// + @Var(Scc_size)
1 C- O# j1 }5 ?' p0 O0 u3 p// . `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)
3 D' D' D$ r$ I& q# H: X, {//} Variable-Annotation
5 N: i G, s: ~. W/ L+ i! l7 ~! ytemplate< class _Weight_Type> Tarjan_SCC< _Weight_Type>::Tarjan_SCC( const Graph< _Weight_Type> * _graph)
" t5 V: j( a2 x7 O0 ^5 j8 k :. o2 u: C1 H2 ^$ U: }& y
ptrRef_graph( _graph){
9 |- A' J, O; ? ptrNew_queue = new int[ ptrRef_graph->Get_pointsCountMaximum()];$ R4 j2 M) D8 a- k- L
ptrNew_isInQueue = new bool[ ptrRef_graph->Get_pointsCountMaximum()];$ c7 M! X! `& K5 o( c" `7 n2 I/ z# H
ptrNew_sccId = new int[ ptrRef_graph->Get_pointsCountMaximum()];
( R; r0 e5 T* [6 ` ptrNew_sccSize = new int[ ptrRef_graph->Get_pointsCountMaximum()];
0 J7 C4 {. f- S0 @& ^ //--1 h- o4 \$ B4 M6 r7 q3 V. i1 R
Scc_id = ptrNew_sccId;
7 V, m0 e$ U2 i, {0 e# u5 K0 |3 h Scc_size = ptrNew_sccSize;
( M( J4 B2 a) p( M# }# n; X}' |+ b4 t. Y$ [- X& D, T
template< class _Weight_Type> void Tarjan_SCC< _Weight_Type>::Initialize(){% ~+ v7 v1 J- h" U- g
queue_tail = 0;1 ]; I. e; N! Y& f- Y
dfsOrderId_counter = 0;2 e1 V2 z: p) U# o; v" M) k
memset( ptrNew_sccId, -1, sizeof( int) * ptrRef_graph->Get_pointsCount());
" B& @9 A* B; F* B- {" Z! A scc_id_counter = 0; _; G+ C3 H2 D2 ]
for( int i = 0; i < ptrRef_graph->Get_pointsCount(); ++i){& C1 T. z% b+ K) c/ t \
if( -1 == ptrNew_sccId[ i]){
0 X8 |, e. S1 x% U! V dfs( i);
. [' i' a0 R1 q# m4 o5 y }2 D; G+ {2 M/ S" @
}/ h* e4 k$ m7 i4 Z* ]" l2 G
}$ z* p) I. S! e8 y( H5 K$ @
template< class _Weight_Type> const Graph< _Weight_Type> * Tarjan_SCC< _Weight_Type>::Build_DAG() const{# L V J! j5 u0 U$ Y) u6 J
//< + Make sure @Func(Initialize) has been called$ ^ K5 w2 _# n+ V9 {
Graph< _Weight_Type> * DAG = new Graph< _Weight_Type>( scc_id_counter, ptrRef_graph->Get_edgesCountMaximum());6 i# T0 z1 }' o( ]9 {. S, f ?+ Q
DAG->Initialize( scc_id_counter);
' b. x6 K$ `1 R* L& i' E) s for( int a, b, i = 0; i < ptrRef_graph->Get_pointsCount(); ++i){
9 ~9 k* J, C4 c3 Z$ s7 g for( int j, z = ptrRef_graph->Head[ i]; ~z; z = ptrRef_graph->Next[ z]){
/ |" n) D, P5 o j = ptrRef_graph->Vertex[ z];9 R$ x2 v9 X3 @+ q- E4 Z
a = ptrNew_sccId[ i];
1 }; `1 Q1 J3 ]5 D* S8 d7 w) m b = ptrNew_sccId[ j];
S/ i0 w- n1 a+ Q; X+ } if( a != b){
9 x. u# ^1 ^# [* `2 ` DAG->Add_edge( ptrNew_sccId[ i], ptrNew_sccId[ j], ptrRef_graph->Weight[ z]);
) H: q8 j. ]+ T }5 x0 ^- t, H( J9 u$ `# }6 q5 r
}
. c% [7 w) @) F' [ }
& ~! ?5 U1 L% s$ i2 Q& { return DAG;
. l# @7 A7 s* R8 Y9 }' E}2 `; S x X% l% y& }
template< class _Weight_Type> const Graph< _Weight_Type> * Tarjan_SCC< _Weight_Type>::Build_DAG_uniqueEdges() const{* g" Z( M, C3 \$ }% \- [
//< + Make sure @Func(Initialize) has been called; m2 e6 _/ W9 ^7 e7 x+ v G8 T
//< + There is at most one edge between any two points in the DAG (i.e., @Ret)
8 F' D5 Y) n) \2 K' Y unordered_set< long long> hash_edges;3 I% T7 R7 @$ b) ^. v; {7 ~
Graph< _Weight_Type> * DAG = new Graph< _Weight_Type>( scc_id_counter, ptrRef_graph->Get_edgesCountMaximum());3 ], i& `6 P' L
DAG->Initialize( scc_id_counter);
; R& n! T" X: D4 |) W for( int a, b, i = 0; i < ptrRef_graph->Get_pointsCount(); ++i){
7 m I2 u9 h, G v, c for( int j, z = ptrRef_graph->Head[ i]; ~z; z = ptrRef_graph->Next[ z]){6 Z! `9 ?* d' @; {+ o* \' t/ D" w
j = ptrRef_graph->Vertex[ z];4 M' c) _5 \ x! F
a = ptrNew_sccId[ i];7 U% j- H9 |1 ?7 q* H1 `) m9 v9 A
b = ptrNew_sccId[ j];
9 G% N, S7 ?' D$ x if( a != b){9 }9 @' ], ]- {$ h, L B6 H. E8 h9 `( ]7 N
long long hash_val = (long long)a * scc_id_counter + b;' z% r T' u+ J! _9 b
if( hash_edges.find( hash_val) != hash_edges.end()){3 H2 S2 b& v [! p5 Q' V- @* m
continue;3 b7 {& `' @) Q4 Z
}( N( L4 C/ l2 P5 ?. Y& @' t: Q+ I
hash_edges.insert( hash_val);
5 Y2 G( E) W) G: W& ]: w1 ^ DAG->Add_edge( ptrNew_sccId[ i], ptrNew_sccId[ j], ptrRef_graph->Weight[ z]);" I$ Y$ F! j- P. b( U
}, }, b7 u+ f/ b8 }1 }! M$ B+ H' }3 h
}0 S7 q4 s) h" d1 O1 V0 [; x. i
}0 S1 I* x3 N; r9 E4 ?( \+ p
return DAG;' i: X6 c4 J4 c M, @
}$ p u4 o ` [. _7 q
template< class _Weight_Type> void Tarjan_SCC< _Weight_Type>::dfs( int _cur){5 d: ?8 s' ~: s# C! S& `& d+ B, v
ptrNew_queue[ queue_tail ++] = _cur;
: e$ A! d7 y( l0 U* e' V7 D3 o3 _ ptrNew_isInQueue[ _cur] = true;
0 _* A4 v0 T5 A, X1 j& Y6 @, _6 ]7 r int current_dfsOrderId = dfsOrderId_counter;
' n( q3 y3 X* s5 ~: X P* g2 C( t# G ptrNew_sccId[ _cur] = dfsOrderId_counter ++;, Z( J' i% @4 ?
//--
% @) n ?+ [! y+ r for( int nex, i = ptrRef_graph->Head[ _cur]; ~i; i = ptrRef_graph->Next[ i]){
! x8 l: o' F2 i" w1 X nex = ptrRef_graph->Vertex[ i];
7 p5 p3 b1 _1 o& R) u+ K% u3 l if( -1 == ptrNew_sccId[ nex]){
% B+ ]! t" N k* a. w1 q1 e# r5 H: s dfs( nex);$ ^- K* s4 B& u- A" Z8 P v1 R
}
- u7 ]* Z9 @( }9 R G if( ptrNew_isInQueue[ nex]){
3 {& K! A0 _8 a- a1 ^ ptrNew_sccId[ _cur] = min( ptrNew_sccId[ nex], ptrNew_sccId[ _cur]);
; }. I' U, a7 @; o; P, \ }
5 V$ @' ? n& a/ a$ K0 h- C F }% \" S$ O7 I- Z. ?4 P8 m6 G9 P
if( ptrNew_sccId[ _cur] == current_dfsOrderId){
! t, a* D, H* m7 o ptrNew_sccSize[ scc_id_counter] = 0;
& J Y9 l" e: J# O while( true){
- {3 ^: y+ F& U9 b int c = ptrNew_queue[ queue_tail - 1];# {, @6 Y: V5 g/ S! p' n7 D
ptrNew_isInQueue[ c] = false;
3 ^& ?% i8 t6 w2 O# [ -- queue_tail;
; A( A! Z3 n6 E* c5 n ptrNew_sccId[ c] = scc_id_counter;
! F# e* M/ M& E7 \7 _0 G ++ ptrNew_sccSize[ scc_id_counter];
8 V1 H( c1 l% T if( c == _cur){ break;} R2 A4 b0 T( q, E! ^5 o
}
9 E, Q2 `1 ]: F ++ scc_id_counter;' C& S7 Q9 ` p0 P
}- L) b' h8 I+ I+ _5 ? C' W
}" m7 H2 W1 Y) n& B: Q- E
//} Tarjan_SCC/ _. p+ y( d+ B& u
" Z4 b1 d: K7 B% Q5 [% B
差分约束系统,不等式组
0 s4 w- y; P6 g/ [( A( J//{ Minimize_InequalitiesSystem
6 _+ y- R0 q3 u0 Atemplate < typename _Edge_Type, typename _Distance_Type>' F3 R; ]$ I) [7 x7 w
class Minimize_InequalitiesSystem{
0 t/ j9 p5 p+ {+ j$ epublic:
4 j2 V+ B! B8 v3 W" x9 c const _Distance_Type * Distance;
% b9 \- N; @0 j9 i3 j1 V6 g8 b9 U: W //-- variable ends# U, A$ D& P* x7 G* ?5 `5 y8 d
Minimize_InequalitiesSystem( const Graph_Weighted< _Edge_Type> * _graph)
- e/ s# p N$ L2 }8 b8 z+ M :+ Y i% ?" G/ A6 R
ptrRef_graph( _graph){" u. N z! V; t# N7 Y1 D6 O8 z
ptr_distance = new _Distance_Type[ ptrRef_graph->Get_pointsCountMaximum()];- G6 C' C7 T u4 B. l8 {1 _
Distance = ptr_distance;& D! P0 k4 y3 y+ L! o: O
ptr_isInQueue = new bool[ ptrRef_graph->Get_pointsCountMaximum()];
/ @2 G) |2 m; u; m2 P" v ptr_queue = new int[ ptrRef_graph->Get_pointsCountMaximum() + 1];4 w* H) W( L' Z/ } K
points_range = 0;1 {! V2 w2 \) m# e8 V; W
ptrNew_pathLength = new int[ ptrRef_graph->Get_pointsCountMaximum()];
9 V$ F5 M! M7 Z* ~ //--
( O8 G1 r) c9 r0 g Initialize();
+ g9 c3 u3 ^2 a* N: q }
, z; ~5 d2 R% L! W void Initialize(){4 V6 e2 I5 E# i
points_range = ptrRef_graph->Get_pointsCount();
, E4 {3 {+ F# o) j `$ V }" V c# \( V% G% i8 \6 U
bool Work(){
' j/ x3 P/ S( p) ^ memset( ptr_distance, 0, sizeof( _Distance_Type) * points_range);
8 v- c0 G l3 L; q& K4 d9 ?1 s9 u' r' @ memset( ptrNew_pathLength, 0, sizeof( int) * points_range);1 U/ z/ S1 O, `2 z
for( int i = 0; i < points_range; ++i){
8 G8 |$ j3 }8 a9 [6 s& [ ptr_queue[ i] = i;7 V5 Q2 q) S6 D, R! N) Q) m7 V
}
! J# b# f9 h2 b memset( ptr_isInQueue, true, sizeof( bool) * points_range);; z0 v' u. U7 M$ c% g. E
queue_head = 0;
! I9 m0 R7 [4 W1 C queue_tail = points_range;( f3 q5 S. i* H6 q; o# Z
//--8 i9 p4 G- ?+ j* |
int cur, nex, edge;
7 S. c o' ^# Y7 r3 K+ g8 W while( queue_head != queue_tail){
4 g! B% }; ]6 P3 { cur = ptr_queue[ queue_head ++];5 P9 m9 p. e% m2 ?( ^
ptr_isInQueue[ cur] = false;
5 e% r( H/ |( ?* V if( queue_head > points_range){ queue_head = 0;}
9 R/ ~! M9 U$ q6 T9 f for( edge = ptrRef_graph->Head[ cur]; ~edge; edge = ptrRef_graph->Next[ edge]){
) I- m' S4 l8 s: k& P/ D6 [ nex = ptrRef_graph->Vertex[ edge];
5 f7 n$ J; g9 u% P3 O& y: L if( ptr_distance[ cur] + ptrRef_graph->Weight[ edge] > ptr_distance[ nex]){
; ?. x1 Z4 \* E ptrNew_pathLength[ nex] = ptrNew_pathLength[ cur] + 1;
8 L. l0 m. T; M' S B) f' h& b! c if( ptrNew_pathLength[ nex] >= points_range){
0 k" M/ @: y+ y h. S L* x6 R8 n return false;
* `9 \6 w* u- K: C$ V& o }- f1 A2 I, R& P; `( }( _4 U
ptr_distance[ nex] = ptr_distance[ cur] + ptrRef_graph->Weight[ edge]; W$ x/ C y. ^9 ?# W+ y( S
if( false == ptr_isInQueue[ nex]){
?0 g( }9 }; N; L, [: l1 R% A2 y; a ptr_isInQueue[ nex] = true;
0 |( W" Y0 A* R) A3 Q6 F ptr_queue[ queue_tail ++] = nex;% E* S* p; h+ [- f0 F5 u1 L% d
if( queue_tail > points_range){ queue_tail = 0;}- I8 F2 R$ }6 [% k. _+ _- l+ h
}
, a6 S9 n: Y7 u) G. U }
0 M4 G2 S3 M1 |" w4 p }
) x$ w1 X: }8 Z6 M% O W1 J }
& y9 \) z' G/ g return true;9 L6 X: w3 y' z9 n% [
}
# m$ P+ z7 U+ eprivate:
8 `) O( a( B' M% A, D$ B' ] const Graph_Weighted< _Edge_Type> * ptrRef_graph;- y% J/ s/ {! }" y
int points_range;
' S; u" T9 D6 P- O _Distance_Type * ptr_distance;
6 u# q) N/ h* l0 _ c bool * ptr_isInQueue;
: p' l' E- V, s% }9 V int * ptr_queue;/ d" `% H& ^" d) l& t
int queue_head, queue_tail;1 A& B/ F2 Q( U% ]8 r
int * ptrNew_pathLength;3 N2 }* [ `% c
};- N, ^- }' W5 _$ {4 E' L
//} Minimize_InequalitiesSystem
# P o0 }: L- |
- o6 h/ ?1 Z+ BCaution
& F* i9 r$ X! Z
8 M; H `% ]- e`+` You should never modify the source-code of @Func( Work), otherwise, it means your algorithm must be erroneous.! o7 w4 t5 `8 i) e4 o
1, X$ D$ s" d" C& Y! i
Annotation
9 v* t m; h6 E0 V% f4 j* r8 T9 H1 f! R, s0 g, l4 U- \1 m
`+` @Func( Work)8 s* l1 i! a( q: h. Z/ A
`1` `@Ret = true` means the Inequality-System is Consistent, otherwise it is Inconsistent (No-Solution). j" P0 b3 D; X# |& T7 I' x* B
`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`;) u9 t4 r7 i% s+ U& g: ^
`.` In other words, under the premise `all variables xi >= 0`, minimize every variable and also satisfies all relations (i.e., the graph)( m/ D9 f4 E9 T( _
& R2 m* h( S8 f) s: D3 C6 q5 h
`+` @Var( ptrRef_graph)4 H" n, C6 [5 }/ k- N6 }
`.` 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.) T& `: D; ~. O9 l' X+ u9 W( V, ^
* v5 V) ?( t, M2 D9 [/ a: L% F
数论
8 S( j% s; r5 x! V矩阵乘法7 b9 j X9 \! I' j+ D
//{ MatrixMultiplication-Declaration
) l- G; H T/ e6 u. b& |* _template< class _Type, int _MaximumLength>
" W3 S/ C0 p: u# O6 t7 g" aclass MatrixMultiplication{
1 b* ]$ @9 D* G/ E% a+ gpublic:
6 U7 x, g' {; U+ P/ } MatrixMultiplication( _Type);3 l d0 y- B' [2 h
void Initialize( int, _Type (*)[ _MaximumLength], const _Type (*)[ _MaximumLength], const _Type (*)[ _MaximumLength][ _MaximumLength], long long);
" O f' M$ ?" vprivate:
( ~; h. f2 q6 K/ l% W! G& ^ _Type modulus;
, k& G8 k+ V/ Q& B$ X int length;
1 N5 Y% {0 W! ~0 D. ?5 [. |1 P _Type factor[ _MaximumLength][ _MaximumLength];5 [3 B0 F6 t) i
_Type answer[ _MaximumLength][ _MaximumLength];
$ K5 r% C" B6 i. h* m _Type temp[ _MaximumLength][ _MaximumLength];
0 e$ M8 x8 T5 h/ Q# M //-- variable ends
7 R- T, ]! A v; N' b8 t) w9 ~; S void matrix_multiplication( _Type (*)[ _MaximumLength][ _MaximumLength], const _Type (*)[ _MaximumLength][ _MaximumLength], const _Type (*)[ _MaximumLength][ _MaximumLength]);
5 w4 o* U% Y" O. D};$ n5 H; c, z7 Q4 m+ `+ [3 @! n
//} MatrixMultiplication-Declaration
( h. D# {. B& U6 `$ Y% X6 v) S! }0 F& C$ {) W! S
//{ MatrixMultiplication-Implementation, w, l5 }+ y' N7 n8 `6 t1 N% b
template< class _Type, int _MaximumLength> MatrixMultiplication< _Type, _MaximumLength>::MatrixMultiplication( _Type _modulus)
' ^" H( B% {: ^& g) J' x' s/ h5 ] :
2 a; b+ `: M }& S modulus( _modulus){
& `5 v, }, y( t. ~, Z$ X4 T}5 z/ i$ G5 r' `+ o2 C2 h
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){# W6 V. ^0 s! L2 v
//<
4 [# V( s t) o// @Brief7 k- a' k7 a# F' I& h; R# }( ]) P
// . `result = dp * (factor ^ k)`;
2 I% S% ]& f2 X! V! g* ]- L& g$ k6 e0 K// @Warning; E3 g- x& ~8 W7 m E" j0 ^7 s
// . Make sure the data of `dp` is `dp[0, ..., _length)`, the data of `_factor` is `[ (0,0) -> (_length-1, _length-1) ]`;1 D3 ~) W) _+ Y7 a
ASSERT_( _k >= 0);$ Z: p; K6 d; w( Q9 `3 P) O' K
ASSERT_( _length <= _MaximumLength);
, `( U- A! d1 u/ o/ a: m //----+ G; C9 o1 a; {$ V6 F
length = _length;5 M3 H) o# y& \# ?8 R8 B0 k
//--% T9 o- }5 C; z) g9 s
memset( answer, 0, sizeof( answer));- T0 g7 L; T5 g
for( int i = 0; i < length; ++i){* f' q, V. j* R# S$ d
answer[ 0][ i] = (* _dp)[ i] % modulus; if( answer[ 0][ i] < 0){ answer[ 0][ i] += modulus;}6 ^# p2 l) d5 x! v/ E. }) A2 Q! I
}
+ a5 c4 f, j. L$ o for( int i = 0; i < length; ++i){
$ |) D) u J& G: f for( int j = 0; j < length; ++j){( h+ D" R% m2 d' o* A% M' \8 o
factor[ i][ j] = (* _factor)[ i][ j] % modulus; if( factor[ i][ j] < 0){ factor[ i][ j] += modulus;}% r1 M/ V" R% ^7 W
}
, r7 v" T6 U! I$ v8 G }
" u3 Y! i1 J5 L+ q! L! S" R+ A //--1 Z5 N; ?! d5 z6 s# s. X
while( _k > 0){% X$ K2 Q, }! q3 f5 ~& g9 N
if( _k & 1){6 W* v( T7 _0 _8 ~
matrix_multiplication( &answer, &answer, &factor);# U2 {# G& o+ a4 x
}* t3 `9 r. K& j- R& q5 c
_k >>= 1;! i2 x& o; n# ?3 q% I
matrix_multiplication( &factor, &factor, &factor);5 `9 U; {0 `# U2 v4 b; b$ L1 L) Q
}' R$ g- v3 E* C8 k1 i$ j
//--2 B8 s# Q T* M3 v4 ~) h
memcpy( _result, answer[ 0], sizeof( _Type) * length); // the address of `_result` equals to the address of its first-element;
- k! Z$ A: [, [& H}
; q# {7 ^5 U8 N9 U# i- Ztemplate< class _Type, int _MaximumLength> void MatrixMultiplication< _Type, _MaximumLength>::matrix_multiplication( _Type ( * _result)[ _MaximumLength][ _MaximumLength], const _Type (* _a)[ _MaximumLength][ _MaximumLength], const _Type (* _b)[ _MaximumLength][ _MaximumLength]){
8 i/ F% Y* M* V. g/ x. F- g//<
' M: P' {6 R# P2 q& ~- @// @Brief& b8 q6 X2 @: Q; e
// . `result = a * b`;# Q- g9 X0 r9 a( s+ p
for( int i = 0; i < length; ++i){3 K$ e5 \7 n% F' o( L
for( int j = 0; j < length; ++j){
( Z. m) p9 C- h* N4 u# W //>> Cuz `result` maybe equals to `a/b`, you need store the result to `temp` not `result`;0 r7 K& L' D: _' D }' w, g; \+ L
temp[ i][ j] = 0;6 Z f6 Y( f0 i/ m, C
for( int z = 0; z < length; ++z){3 c* h9 q/ p% V
temp[ i][ j] += (long long)((* _a)[ i][ z]) * (* _b)[ z][ j] % modulus; if( temp[ i][ j] >= modulus){ temp[ i][ j] -= modulus;}
- O5 R* ~4 }9 a% v& C7 X0 Y2 d }
7 v& ]* ~: i6 W0 x' ]5 ? }
( S5 L* D/ j | }
! b$ w: B$ `1 h2 o+ b memcpy( _result, temp, sizeof( temp));; ?3 _6 C% w: C, _# }9 L2 ^) c
}" o2 q- i( t& m
//} MatrixMultiplication-Implementation% w) F9 F7 e, U d6 Q4 D
g, L8 e/ f! X/ p@Delimiter
0 T+ c- Q- F" D2 j7 u) W5 E; E
& W4 {7 s" E/ `! y( i" t示例; d8 G# Q3 I5 N* V% I4 T+ x/ E
4 _. G7 k8 j- {, p% kint Dp[ 4] = {1, 2, 2, 1};" k) E5 ~& x8 _- d5 X
int A[ 4][ 4] = {{0,1,0,0}, {1,1,1,0}, {0,0,1,1}, {0,0,0,1}};
9 w+ ]1 l) d( G% d, V9 zMatrixMultiplication< int, 4> Mat( M);/ V3 k) w- [5 w. t) @* n/ ?; @2 s ]
Mat.Initialize( 4, &Dp, &Dp, &A, N - 2);3 Y: b2 H0 A5 N0 c9 Q' r% w
0 I; I/ g. _8 f$ K* m
long long ans = (long long)Dp[ 2] * N % M - Dp[ 3];
; b# T8 M& Q G$ O- Fcout<< ans;: Y5 W+ ^' X, h% x- R
13 `. {9 P5 {. d6 l3 H. D1 V
2
! Z+ G; n+ T# e5 d) X0 N3- @! m7 ~2 a$ }( p$ e0 r
4
1 @4 p- O* I) c0 T8 x56 `3 |( [8 T9 H& }
6
! S1 u1 y. T5 G7 F7 ? d/ b/ U7
0 H2 R. ]: M% n中国剩余定理3 l5 T7 J& I$ h U9 R! t
朴素 CRT
& v! k# R# H+ e7 K: {! L- ^9 e//{ CRT-Declaration& }& v; g+ R. T$ c5 s- N
template< class _Type> pair< long long, long long> CRT( int, const pair< _Type, _Type> *);6 a: m: ^- R3 @+ u/ I/ w2 R9 C6 C! X+ ^
//} CRT-Declaration
0 s8 y0 |. S0 ~, m5 Y0 F
? H8 c) g* U; T7 y; N//{ CRT-Implementation. V) m* z: R! O
template< class _Type> pair< long long, long long> CRT( int _n, const pair< _Type, _Type> * _arr){; q3 M& X; f0 T( Z7 O+ u$ _
//<0 b% D+ ]3 d+ s4 D1 G) Z
// @Brief
) A) @$ {8 m( H$ v" h8 Z// . Solve the system of `n` Congruence-Equations represented by `arr` (i.e., `? = arr[i].first (% arr[i].second)`);, a* d. u5 D4 q( y! b5 E8 F7 F& P
// . Once all `arr[?].second` are Pairwise-Coprime, this system must be Solvable (and Infinite-Solutions);
* i7 W0 r' d2 G// . @Define( `(a,m)` = @Return), `a` must in the range [0, m), and the Solutons are $a + kk * m, \forall kk \in \Z$;+ ~+ q% t* s& `) k" }: A0 O1 D
// @Warning( h: B& u) z& l7 Y* o0 e8 e
// . Make sure all `arr[?].second` must be Pairwise-Coprime;7 z$ D% Z* C5 P: b9 Y; C
// . Make sure the Product of all `arr[?].second` in the range `long long`;- _8 a, a N+ {: Y
// @TimeCost9 z& M |; n2 r2 ~& ?
// . $n * 60$;0 ]" B4 U# g' E
long long M = 1;) X7 _* O6 t, b1 _+ L
for( int i = 0; i < _n; ++i){
0 Y) N1 A/ N% h ASSERT_( _arr[ i].second >= 1);
, a- p" H1 H( ?1 s, v" i, c- J: Z M *= _arr[ i].second;
3 U% Z' a6 i% _* [ y }
, U( O7 `* _5 q( K- \) W long long answer = 0;/ I. c' z Q2 ~6 H. I+ B- w9 O
for( int i = 0; i < _n; ++i){
8 C- u7 {0 P( c* i _Type a = _arr[ i].first % _arr[ i].second; if( a < 0){ a += _arr[ i].second;}
6 H% \4 o# v ^ long long m = M / _arr[ i].second;9 F2 c1 B4 ^' |4 K9 i2 |3 T$ _ a1 H
pair< bool, pair< _Type, _Type> > ret = LCE_BezoutE< long long>( m, 1, _arr[ i].second); // m * `ret.second` = 1 (% _arr[ i].second);4 j& l1 S" q% j1 d4 B2 r7 h
ASSERT_( ret.first); // All `arr.second` are not Pairwise-Coprime which rebels the Premise-Of-This-Algorithm (See @Warning);
2 r( H2 f; \+ g4 E answer = (answer + (long long)a * m % M * ret.second.first % M) % M; u( H4 E1 ^8 v" @* V' G
}; r" A; J' P3 s* [5 }) b; l
return {answer, M};- Q1 D3 w& _0 ?, o0 R9 `9 R
}
) d" |. G+ l% r! x' z3 n//} CRT-Implementation
( ~2 K: g: a/ ` @) i
( y7 [. R6 E) y9 R0 s+ t拓展 CRT_EX7 z/ b# [% Y# m8 l- c# i8 U
//{ CRT_EX-Declatation
- x- J" O. T! S* x3 W- t# R3 gtemplate< class _Type> pair< bool, pair< long long, long long> > CRT_EX( int, const pair< _Type, _Type> *);8 x. z# `/ n. m2 V& l9 z. h& ]
//} CRT_EX-Declatation
, w9 `8 W; y! n$ h( D; y( ^. m
//{ CRT_EX-Implementation+ o" n1 ^8 O1 q _, v
template< class _Type> pair< bool, pair< long long, long long> > CRT_EX( int _n, const pair< _Type, _Type> * _arr){; `6 |) Y5 W; q
//<9 w. Q! s1 I9 I' Y9 L% F% R2 A* O
// @Brief2 M! `9 @6 N6 p- G& \' V8 }
// . Solve the system of `n` Congruence-Equations represented by `arr` (i.e., `? = arr[i].first (% arr[i].second)`);, [6 a: Y8 G% \6 n
// . @Define( `(r1, (r2,r3))` = @Return);7 S7 L: b) J! ~# T
// 0( r1=false): There is No-Solution;
+ D0 z/ a. y/ q; u1 g; `% }# S// 1( ELSE): The Solutons are `r2 + kk * r3, $\forall kk \in \Z$`, and `r2` must in the range [0, r3);% N# h; C+ l0 r; N1 U. n) g& m1 g
// . All `arr[?].second` maybe not Pairwise-Coprime (which differs from `CRT`);
; _1 z) w0 a0 B' t/ _4 n// @Warning2 L* Z c" Y+ s$ s. U( M
// . Make sure the LCM (Least-Common-Multiple) of all `arr[?].second` in the range `long long`;2 q8 ^( q2 V1 B- e) ^; c8 w l
// @TimeCost* T. i' M3 N9 \4 z" u; z% ~8 h
// . $n * 60$;
g: @& _) [3 C; \9 J8 \ pair< bool, pair< long long, long long> > answer;
% o6 X5 v2 t" u. k" {/ O5 z long long A, M;. f1 m6 q. R3 c0 N T
for( int i = 0; i < _n; ++i){
4 B4 K" b8 d9 h/ C; d( _ _Type a = _arr[ i].first;; D2 o" c2 L) |2 w3 N( h( V" K( N
a %= _arr[ i].second; if( a < 0){ a += _arr[ i].second;}
0 P8 }3 |/ G; D& N% |+ M //--
! n1 n# K6 `/ o1 V+ G8 X* J$ u% T. D. \' K if( i == 0){
q$ n% d/ l. ?( }' T- C A = a, M = _arr[ i].second;
9 I& i" ^# j2 _: q; z2 O q! _% R continue;- `/ `4 V4 d" T9 A; S5 M% g
}6 ^5 d% F' B" j. \5 h$ A! V" U4 D
pair< bool, pair< _Type, _Type> > ret = LCE_BezoutE< long long>( M, a - A, _arr[ i].second);
% b* {' u1 X3 C0 } if( false == ret.first){5 M) p: H& c8 c3 f3 K! T
answer.first = false;
1 v+ k4 A/ \8 u; o& s& S4 r8 h return answer;
3 q6 x0 x6 y- D& F% X }
; l0 }& V+ h/ L( B) c2 \% K _Type gcd = _arr[ i].second / ret.second.second; if( gcd < 0){ gcd = -gcd;} // The GCD of `M` and `_arr[i].second`;4 t' S0 e) r% X$ `) o3 j! @
long long new_M = M / gcd * _arr[ i].second; // LCM4 i9 B5 ?# y( R7 ]) v2 }& v
A = (A + ret.second.first * M % new_M) % new_M;7 d- S7 u$ m' R
M = new_M;
5 Q1 P& Y9 U; ~1 B5 D+ _6 x }
4 D& s+ }& V- @! y# y answer.first = true;& ~& C! C: K( J5 y! x
answer.second.first = A;; n. O! N( } s: r3 E( S
answer.second.second = M;
# h2 Z5 \! z! X a' g5 _7 ` return answer;* z! q! r8 V8 }; i) j% k
}
4 z" g8 [$ Q- G2 X- L7 b: Y//} CRT_EX-Implementation, H8 e- q# k" h6 J
11 j' J1 A% J9 T3 N) G+ g) F3 c# @
裴蜀方程 BezoutE
X5 w# E. T/ f& v0 y5 A; o: z//{ BezoutE-Declaration: a5 N7 i. I0 G, c( P4 P4 c$ m4 [
template< class _Type> pair< bool, pair< pair< long long, _Type>, pair< long long, _Type> > > BezoutE( _Type _a, _Type _b, _Type _c);; t6 _0 f! l7 V7 m
//} BezoutE-Declaration2 B+ C5 n& |) x7 U9 V8 b# ~
4 [ I4 Y8 I: ]( Q6 G//{ BezoutE-Implementation
( Z- Q% ?& B# F. A) \template< class _Type> pair< _Type, pair< long long, long long> > BezoutE_extendedGCD( _Type _a, _Type _b){. d8 R5 I+ R) ^$ l& o0 |: O8 v5 A) D
//<
, ^$ j# W" i0 S8 r5 M" X a// @Private
( O+ ` c% P& q# B6 w, [" W// @Warning% N' B# v. W% E' {
// . Make sure `a,b >= 0`, Not-Both-Be-`0`;
1 U5 }+ D8 x1 [# x; x if( _b == 0){
1 k! V' `+ p4 _) r' D- g/ Y return {_a, {1, 0}};- E" U6 u$ o! W( v: ]
}
( _4 r$ u+ I+ G auto pre = BezoutE_extendedGCD( _b, _a % _b);6 F( Q+ A* T7 Z# W% x
auto xp = pre.second.first;2 ?& l/ B0 u( a0 i2 u8 H
auto yp = pre.second.second;
5 D6 p* `4 Y! S0 ?4 v1 b return {pre.first, {yp, xp - yp * ( _a / _b)}};9 N. T, w2 J9 S! Q; W# H
};
% Z# x5 c' M8 Q* \! Ttemplate< class _Type> pair< bool, pair< pair< long long, _Type>, pair< long long, _Type> > > BezoutE( _Type _a, _Type _b, _Type _c){! n$ w. l) e* `' l( ~2 i* t
//<
" @4 \9 m! |/ z- o2 U// @Brief3 D' x* g% U- c. ~
// . Solve the equation `xx * a + yy * b = c`, @Define( `(r1, ((a1,m1), (a2,m2)))` = @Return)`;8 t/ {7 t) v$ B5 @
// 0( r1=false): There is no Solution;
# `/ G. e: c' z( I6 o! E// 1( ELSE): The General-Solutions are `(a1 + k * m1, a2 - k * m2) $\forall k \in \Z$`;
# Y% g4 q/ Q5 @4 M, a. w: H// @TimeCost2 A& s$ e( M) j7 c8 C
// . $\ln(a)$;4 N9 d* |+ ~. ]7 j
// @Warning2 v- K- _3 E3 I$ B
// . Make sure `a != 0`, `b != 0`;
# j5 ^; C- [2 g0 [' N1 Z: N$ Y- T ASSERT_( (_a != 0) && (_b != 0));
( I& I4 h9 q: q( r pair< bool, pair< pair< long long, _Type>, pair< long long, _Type> > > answer;
, w. y( H% S" ^1 ~ bool neg_a = false, neg_b = false;; ?0 j4 u; K3 N; |, R7 k8 v( B
if( _a < 0){ neg_a = true; _a = -_a;} // `x * a + y * b = c` -> `(-x) * (-a) + y * b = c`;
8 F/ {( }1 \1 m; M if( _b < 0){ neg_b = true; _b = -_b;} // `x * a + y * b = c` -> `x * a + (-y) * (-b) = c`;
2 _0 f* o9 w4 A: @; V; O+ c //--
- g5 w6 J: \+ } pair< _Type, pair< long long, long long> > ret = BezoutE_extendedGCD( _a, _b);2 F6 k; Z5 {6 E' N1 ^
if( _c % ret.first != 0){
5 u# s' L4 _& J' P answer.first = false;/ ~% p, e! o6 k
return answer;1 e s( Z* N+ u9 Y; w, y& s$ ]
}
0 N4 V N, F% p1 k answer.first = true;* z, H4 Y$ F, T+ ?+ u7 _8 I) P T1 r
answer.second.first.first = ret.second.first * (_c / ret.first);
2 ~. }9 r. ?: t/ ?7 n' _ v0 } answer.second.first.second = _b / ret.first;% m+ [" g7 C% C4 k5 `, d: s/ I; S
answer.second.second.first = ret.second.second * (_c / ret.first);
. u3 @3 L S3 T0 ~+ k: ] answer.second.second.second = _a / ret.first;9 `7 H e9 _- \
if( neg_a){ answer.second.first.first = -answer.second.first.first;}
9 P {, K# B3 X9 B if( neg_b){ answer.second.second.first = -answer.second.second.first;}
; O* h# L V: e" n return answer;. y4 o5 q$ F0 B2 b$ T+ I
}5 l9 K& t& ]& ]: N' { i
//} BezoutE-Implementation
) t% e: P9 Q1 s" e/ T# R9 y" w( X: d# `% x M# z
线性同余方程 LCE3 v2 F2 W, a" j3 K* k8 S
裴蜀方程法 LCE_BezoutE" @) W% T+ O" f8 ?2 D: M
//{ LCE_BezoutE-Declaration
( }. A0 r1 k7 ^template< class _Type> pair< bool, pair< _Type, _Type> > LCE_BezoutE( _Type _a, _Type _b, _Type _mod);% q; H3 |$ n/ T! \' R [# Q; x
//} LCE_BezoutE-Declaration
: {5 ?5 ?/ U7 _4 V: U6 V7 b t5 s6 m( Z/ k1 [1 I
//{ LCE_BezoutE-Implementation
* Z9 i; T2 G# s. p# A' @5 }template< class _Type> pair< bool, pair< _Type, _Type> > LCE_BezoutE( _Type _a, _Type _b, _Type _mod){
6 l# y+ e' E. O2 N7 p//<0 S+ p' F% M+ n9 X% g, C# o
// @Brief$ `: i, U+ ^4 Q6 s' C! b9 Y: \4 a
// . Solve the Congruen-Equation `a * ? = b (% mod)` where `?` is @Return; @Define( `(r1, (a1,m1))` = @Return);
V: ]: v( [8 Y5 f$ D: ]// 0( r1=false): There is No-Solution;
. O; u( L2 A7 s// 1( ELSE): The General-Solutions are `a1 + k * m1, $\forall k \in \Z$`, and `a1` always in the range [0, m);
6 {8 m4 n' t/ ]* q// @TimeCost
- g: Z. C0 g& X( h6 P// . $\ln(_a)$;
x H; }- c$ L) ] b* }5 ~ ASSERT_( _mod >= 1);, n0 {$ n7 K6 G7 a [
pair< bool, pair< _Type, _Type> > answer;
9 r& p9 r5 h. w( l _a %= _mod; if( _a < 0){ _a += _mod;}0 d/ @2 U* ^3 @. T! \0 R. [ E0 @
_b %= _mod; if( _b < 0){ _b += _mod;}( T; g8 D8 h% C0 W2 `
if( _a == 0){2 L; u: C4 |: H- V7 W$ {
if( _b == 0){, {3 O- H. m6 Z$ m* B; n, c$ F
answer.first = true;' m/ @ o! O* A0 h0 G
answer.second.first = 0;
! W( f# t2 _& Z7 O2 _- ]# t8 e. q answer.second.second = 1;
1 Y" x7 x! l, W; {5 \7 V2 Q# U& s return answer;% ^9 Y. p. `' {! H0 D5 i5 w y
}3 F. y' B) c0 m S/ L# f5 h/ W4 P8 ]
else{
: k7 f/ b$ [# V+ Z/ R9 z answer.first = false;
2 g- }: j4 Q0 ?5 @ return answer;
. j, K2 V& t, l } n9 l9 R% F+ B! F
}( w: L3 Z; |/ ? A, ]" Z' s4 L2 d5 \
_Type gcd = GCD< _Type>( _a, _mod);6 K6 v3 P# m% p* N: L3 N
pair< bool, pair< pair< long long, _Type>, pair< long long, _Type> > > ret = BezoutE< _Type>( _a, _mod, gcd);
! W1 {7 r7 K# B u) i6 O ASSERT_( ret.first);; j4 d' `9 P+ [7 E: L5 N% \- E! {
if( _b % gcd != 0){# I" p' {7 v& X; M0 _
answer.first = false;- T7 }% c' n& C& ^2 Y
return answer;/ z0 x: ?2 p- h h! K# n
}
$ g; _3 z; c1 b9 P! l answer.second.second = _mod / gcd;7 c( d1 L. W( T, V' S0 O
answer.second.first = Binary_Multiplication< _Type>( ret.second.first.first, _b / gcd, answer.second.second);
/ E% ], }+ l' q9 X3 O answer.first = true;0 h) ~! I. ?" T' q4 p( W0 d1 u
return answer;
( q$ `( O( o. x) q9 k}8 D- w. h7 ^' {4 L" p* M
//} LCE_BezoutE-Implementation# L8 g' ]7 O4 W+ o4 t8 ?
5 T3 Z. ~9 q+ x/ ]高斯消元线性方程组
6 @$ Y' n& m" p: z9 [2 t//{ Gaussian elimination" C3 w* F# h/ L& \2 i" J: B
double Aug[ 105][ 105]; //< @Abbr( augmented matrix)
7 f, d. b+ W: Y7 @; N! i/ |! c) O) |int Gaussian_elimination( int _m, int _n){
2 q+ i# p: C/ D2 o! r. h; x- R//< @Par( _m): the number of equations1 N6 E* d# e0 K8 T; J3 {+ N
//< @Par( _n): the number of variables0 O+ T/ S, S6 U
//< @Return: (0 is unique solution), (1 is infinitely many), (-1 is no solution). e x1 I/ Q& r
int rank = 0;
" B. l% q# k6 `$ k i( m for( int col = 0; ( col < _n) && ( rank < _m); ++col){( }3 R6 n# g- v2 h
int max_row = rank;, C# W: {1 v' p' P4 ?$ P7 Z
for( int row = rank + 1; row < _m; ++row){9 j5 Q4 m" d% m' P3 V( K
if( fabs( Aug[ row][ col]) > fabs( Aug[ max_row][ col])){+ p9 Q$ A4 j( p1 E
max_row = row;, g3 |' Z- A: x- g2 v9 d3 o
}, _( C# v2 F! ?% @8 X. K/ Q9 I# T9 Z
}
1 p3 U. S9 f) v/ J& L0 I7 z* X if( 0 == Db_cmp( fabs( Aug[ max_row][ col]), 0, Epsilon)){5 ?$ _0 `. {% n# g0 M
//* either no solution, or infinitely many.; L' M ~3 m& r; c$ W
continue;# O x" r1 R7 r$ }; l& {3 j
}4 N6 M, Z+ c1 G! Y$ f) J: o
//{ swap two rows& ^% c. k* j" @; Z* i9 N. ^7 ^ r
for( int c = 0; c < _n + 1; ++c){2 X3 P: }4 E1 @/ V' d; M. E
swap( Aug[ max_row][ c], Aug[ rank][ c]);8 H! g! C. ]2 x& N1 U
}" ?% d2 _, S& X* z8 B
//}2 o# X4 s1 j e7 h7 L3 I w
//{ make current pivot to `1`, @) A- `/ U% t3 ~- D
for( int c = _n; c > col; --c){
+ }% O* b0 u& i W4 y+ }& S n; K Aug[ rank][ c] /= Aug[ rank][ col];! I4 |8 g' j: G: @9 I& [2 V) ^/ H
}/ |3 j; Q1 A7 t) w( T' `
Aug[ rank][ col] = 1;
/ F# t/ D) J2 l5 V //}
) T: G6 q8 H: c F ? //{ make all rows below current pivot in the same column to `0`: q `- G6 A0 X/ i& l
for( int r = rank + 1; r < _m; ++r){
+ n: ~2 O7 V* Q9 N7 o# { g if( 0 == Db_cmp( fabs( Aug[ r][ col]), 0, Epsilon)){
8 |& j: h+ a7 f; Y- M7 F- ^) v continue;
8 G9 i; h8 o9 M7 q0 ~; z. L }; `9 C n. F4 L6 F7 Y0 r: T1 U7 p
for( int c = _n; c > col; --c){9 D: }0 l& |% R$ J5 _% [. X
Aug[ r][ c] -= Aug[ r][ col] * Aug[ rank][ c];; B% D$ K) B6 \% s- y, O$ C# X
}9 S5 T8 \2 L: X; I6 k. k* O+ v/ Q
Aug[ r][ col] = 0;' M1 o: @& R: |) l/ K8 ~
}0 Q( i8 `" M" Q6 X* u
++ rank;
- O4 W6 ]; r* l% G& l, [ }
, l. _/ p0 M- G8 s) u: A& I$ U //--8 c9 q% H- \. W3 u
for( int r = rank; r < _m; ++r){
0 Q6 X) q( }) b/ u. @: L if( 0 != Db_cmp( Aug[ r][ _n], 0, Epsilon)){0 Q2 c, Q w# z2 p' j
return -1;& z" U/ g9 f4 g5 h) L
}) v: [6 h1 E' J4 z: `2 V
}
' C& b, ^1 [2 A if( rank != n){+ u1 Y- {( D2 p# |9 s
return 1;* A! q/ \/ _: R% S
}: e B" H% {0 i" e5 W
//> the upper-left `_n * _n` submatrix of `Aug` is a identity-matrix
. F+ n/ z0 \6 H j& x for( int r = rank - 1; r > 0; --r){
7 d, ~! b9 A& }- u for( int rr = 0; rr < r; ++rr){' C. ?$ J$ X _5 d2 X8 U; t: ]! R
if( 0 == Db_cmp( Aug[ rr][ r], 0, Epsilon)){
. l2 w5 A9 v8 B; c continue; G$ h7 C, c+ Q4 ?( Y9 o
}
% X( |' R, |9 K& m; r5 ^( m( ~ Aug[ rr][ _n] -= Aug[ rr][ r] * Aug[ r][ _n];
# g Z: F3 P" S Aug[ rr][ r] = 0;( Q# ?3 G2 K" s* s# [4 p
}3 [. M6 Q) u) b& m
}
. p, Q& E; m- M- m: G return 0;5 i9 X8 y# V- n# s/ C [
}) N6 i- S5 {, S+ n3 R) X' g2 d
//} Gaussian elimination
, D4 y2 o7 d$ U9 V* s( T4 |5 V% w' R
0 Y" L; J" I# a" p: O b- m |
|