|
|
算法 {算法代码模板,算法模板编写规范}0 B3 m* n. Q& _0 @+ C
supimoTemplate.cpp
/ y" g* Y3 V( R/ E) T# r; p! u" d代码
+ f5 U+ B$ W% a# a! V8 f, B1 e3 l#define ___SUPIMOenvir_
5 h8 e8 K0 L5 k+ R1 I1 ^/ W- f! o g: C3 f# S
#include <bits/stdc++.h>
' a: F0 g2 [/ M% tusing namespace ::std;- A- e" U m9 D7 g) Q" ]
G6 K- y4 P2 T! g ~9 ?/ Z#ifdef ___SUPIMOenvir_; `$ s7 A# @6 `# V |0 X
#include "supimoDebug.hpp"' k4 z; g' M" s2 ^+ @2 |+ m2 \) h
#else# Q" @3 J, u9 K! \/ o
#define TOstringITEMS_( ...) ""& Y, i7 s% h& P$ c# i4 w3 p
#define DE_( ...)/ X; c! s: z. F5 R, T5 F
#define ASSERTcustom_( _op, ...) assert(_op)) X1 e( r5 J5 R! u! D
#define ASSERTsystem_( _op, ...) assert(_op)8 E' B, r l4 T
#endif
E* f2 I! M/ F0 I
- f) G9 W, p+ s#define ASSERTregion_( ...) __VA_ARGS__
$ E/ k$ I% h. \#define ASSERTsentence_( ...)) h4 f5 _6 T2 `* @* R
#define EXIT_ std::cerr<< "\nExit(2267): Line("<< __LINE__<< ")\n"; std::exit(2267);
# w; R8 K: a! F+ r8 }2 a- R#define EXITcounter_( _max) { static int cont = 0; ++ cont; if( cont == _max){ string str = "Exit_Counter(" + std::to_string(_max) + ")"; DE_(str); EXIT_;}}/ P; S: A( W. K6 D/ }
#define FOR_( _i, _l, _r) for( int _i=int(_l); _i<=int(_r); ++_i)
/ H5 G) X2 `6 s5 {1 B#define FORrev_( _i, _l, _r) for( int _i=int(_l); _i>=int(_r); --_i)
( v. D1 l' x% S# }- G4 Z8 _* i2 W% B
8 D- @5 m; M D& Fusing Int64_ = long long;
. M0 e' @& u- o3 K4 T8 Y
8 K9 s' {) ]1 R/ S/ s$ G, y
, ]+ Q' \/ |4 c5 P. q0 |; [: h) ?+ bvoid ___Solve_oneTest(){( t/ n$ F5 \ a' k. ^. ^6 B
}1 G. @$ D' [0 i+ G& M$ _$ c
void ___GlobalInitialze(){
9 v- P/ B. W" `9 D# T}
. K7 y0 ]1 H3 n6 Nint main(){" w- n# p; G' O1 e. i
std::ios::sync_with_stdio(0); std::cin.tie(0);
% \- J6 m* I, M2 {: O; @ std::cerr.setf( std::ios::fixed); std::cerr.precision( 9);
+ D7 j9 k9 b0 f9 N# S6 ~- ]' L; T2 v4 H std::cout.setf( std::ios::fixed); std::cout.precision( 9);, r9 Z. b$ s$ Q6 @5 x: _4 ?% P0 T
' U. ? n& f9 Z h auto ___Solve = [](){ // Problem-Input
# X5 `* q' J$ a constexpr char MODEisSINGLE = 1; m* `, A- j! d
int testsCount;3 D D' m+ w* R; W5 `; P
if( MODEisSINGLE){ testsCount = 1;} else{ cin>> testsCount;}
6 x9 J M+ _0 U2 j0 V for( int id = 0; id < testsCount; ++id){+ Z6 G% G/ b# w' k
if( id == 0){ ___GlobalInitialze();}5 R; g& Y6 r5 j2 a
___Solve_oneTest();
+ L, f# d/ U8 T+ ]2 p0 c) R }
! q3 E# V# ^" j, i" P9 N5 h- m };
* k/ W8 k5 L2 u7 B) Y#ifdef ___SUPIMOenvir_1 C+ ~' ~* P8 u8 ]/ o4 T4 P
while( 1){
* N' M: [2 i) t9 I6 c1 e& ~% @ std::string flag; std::cin>> flag; ASSERTsystem_( flag.substr( 0, 10) == "#___Input[", flag);: i/ i% e* y6 U) C
flag.replace( 4, 2, "Out");
$ n$ \. \) @" e& p0 q' {; Z std::cout<< " "<< flag<< "\n"; std::cerr<< " "<< flag<< "\n";# J) U( X+ n2 \: l7 s' X
if( flag == "#___Output[-1]#"){ break;}
4 s7 k; e" L$ t2 M+ X% p// int timeStart = std::clock();
Y* _2 K9 N* Z4 x( @ ___Solve();
# u0 x9 o* f8 U" k. r8 T4 X3 Y std::cout<< "\n"; std::cerr<< "\n";; R! m4 E8 S. N1 q
// std::cout<< "TimeElapsed: "<< std::clock() - timeStart<< "\n";
0 b" K+ l# r) D6 H2 T2 i6 F }! l n4 z, ~! s o
#else3 H& q3 r- t! p
___Solve();
# z' u; X- p6 |9 \#endif: k, W2 b# u8 [; F
4 x7 |! T2 l0 ]! u) \& _' ?* _; b
return 0;
# B4 ?% G+ ?- M$ j' \8 U! K}
$ ?2 ^& x/ n7 k6 H3 H- l1
( @, k5 E+ k7 w/ v2) v7 u& s% r+ z4 H) P0 y
3# E( G6 d4 o9 y, f
48 G: m- W2 a5 r9 e# _
5
5 l$ u6 S$ | S/ G! w67 y' S8 g4 i1 y4 |3 ]8 f
71 w- A( x; }0 ?' b* w7 h* m3 x
83 T$ X6 G* j! ]) R# y
9
0 M# m2 w3 `. V9 k. g1 j! L10
& Y `5 g8 q! }1 q$ \ D8 v+ i11
( C4 p3 z4 V5 O6 E12( ?! n: M) a. G( Q6 z$ ~
13
! i9 `: S/ L# n' q+ V8 e+ P14$ @% o6 j' p) r
15& R3 h y8 `" ~& p
16+ c) b: D# _2 g- u; W: [6 U5 N7 z
17
& f: i, i; a6 V& m% e18
$ ], c9 \7 ?( |19, }$ h6 l- T& ^
20
, K- U5 e; _8 d3 N3 x3 s21
% |# p* k! q0 G% ~( s225 q2 ~8 p: U& e8 t3 v4 H6 t! e6 w
23+ W% H6 J$ {1 E! ?
24
! l( `! D+ W& g. i6 [& B253 v/ T0 T; { Y! Y9 R) H6 Y
269 g- k8 h! z/ h% H! w: x5 _
27
; y! l$ `5 P5 m* C& ^5 D9 o28
& A( L4 V% J& u, T }4 A9 o+ z/ T) ]29, }; T. f4 _& M5 k- D
30
" W4 c8 {" k" z% E+ a6 w31/ X& l1 N2 C6 S: g) |
32
' e, P6 {5 v1 ?- A$ Z33
* ~& D$ P( h+ s. L34
2 k" [0 i o. w5 U35
. J0 i! Q8 `& ?9 S36
8 [" [, D3 g* W* G. Y37
! P) c* |( J7 p% ^38/ {( z: a$ s) s1 ~# A
39/ R1 ?/ Q* M/ E( y( x
403 t; ]3 I! j( k3 [! t, S; }4 J
41
+ X! h$ ~% Z! T( b+ l+ K7 v422 t; G5 E' ~1 x8 K
43
4 E7 Y- L9 h) }# j# h# ?44; C3 {+ u R' Y1 F2 x& \
457 e- e: ^* V: l5 i# z( s
46) {+ M5 O% M5 K/ J1 N4 ]$ N
47( F5 _* I* z9 g" ]: D$ y
483 y$ J! ^0 H/ M! }) s+ e7 t- c$ y
49* p% l" G. }" u8 y1 L S+ ?* i
50
5 L$ G; E2 f1 ] }) z* R8 t9 h51
2 ]" h2 v- e0 T0 r Y/ h- w52. u7 d7 A7 H4 i# b# I
532 F) g1 }' {. a9 C( \" E, ?
54$ b+ `0 l {* u
55% u# I) V: J0 U; k
56
1 n2 A9 b4 z; [1 W, _$ Z9 ]# a57
+ U5 \ a0 C! Y4 d7 f0 D9 ?. M5 C8 o58, f8 c* F6 O. P$ e
598 a" v2 q7 q [" t6 ]5 D1 x& O
supimoDebug.hpp3 I, A( |* i6 z
代码
. L% o, g2 r6 g% ~# v8 u#include <bits/stdc++.h>
5 e& H4 c Q" b# O
% C8 K, P0 H: b. f2 y/ K1 }+ h! }9 C#define VARSandLOCATION_( ...) std::string(std::string("{File: ")+ __FILE__+ ", Line: "+ std::to_string(__LINE__)+ ", VarName: ["+ #__VA_ARGS__+ "]}")
& B; h S; P+ e/ W4 }8 v) K' t#define TOstringITEMS_( ...) ___DEBUG_::ToString_Items( __VA_ARGS__)
0 i8 M. B8 u. J p#define DE_( ...) std::cerr<< TOstringITEMS_( __VA_ARGS__)<< " "<< VARSandLOCATION_(__VA__ARGS__)<< "\n"
9 j; M) Q6 M" s9 \#define ASSERTcustom_( _op, ...) if( !bool(_op)){ std::cerr<<"Assertion_Failed(Custom): ["<< #_op<< "] {Hint: ["<< TOstringITEMS_( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< "); Line: "<< __LINE__<< "}"; std::exit(2267);}
6 x5 n( V; N4 ^/ p4 M#define ASSERTsystem_( _op, ...) if( !bool(_op)){ std::cerr<<"Assertion_Failed(System): ["<< #_op<< "] {Hint: ["<< TOstringITEMS_( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< "); Line: "<< __LINE__<< "}"; std::exit(2267);}( l3 c5 d) o% S+ M# S
! P5 i5 B$ w/ [
namespace ___DEBUG_ {
! J4 w2 u! d/ B6 D+ k //>> 所谓`Container`是指 可以通过`for( auto i : S)`来进行遍历的;
3 \) @ h7 m! k' @' m' f6 V( ~" Z# ] template< class _t> struct __IsContainer_Unwrap : std::false_type{};& |4 }5 Z6 z1 @/ _8 }& Z. {/ |) x
template< class _t> struct __IsContainer_Unwrap<std::vector<_t> > : std::true_type{};
2 N' \. d2 D2 t- r+ B: O template< class _t> struct __IsContainer_Unwrap<std::set<_t> > : std::true_type{};
j1 Y, ^$ y8 b' P2 Q, ?% x% c2 R template< class _t> struct __IsContainer_Unwrap<std::unordered_set<_t> > : std::true_type{};
2 N6 t U+ L! V7 }' i template< class _t> struct __IsContainer_Unwrap<std::multiset<_t> > : std::true_type{};1 l- r) b5 D* Y9 I9 g! Q
template< class _t> struct __IsContainer_Unwrap<std::unordered_multiset<_t> > : std::true_type{};+ |& H2 M7 E4 N. l0 v
template< class _t0, class _t1> struct __IsContainer_Unwrap<std::map<_t0,_t1> > : std::true_type{};/ L; R- h0 h0 y5 X5 _' r' @$ {
template< class _t0, class _t1> struct __IsContainer_Unwrap<std::unordered_map<_t0,_t1> > : std::true_type{};
. F" d6 G. h, e$ G template< class _t0, int _t1> struct __IsContainer_Unwrap< _t0[_t1] > : std::true_type{};
. O, f; n7 J a+ \ template< int _t1> struct __IsContainer_Unwrap< char[_t1] > : std::false_type{}; // 特判, 字符串常量"..."不属于容器;/ S4 j, _; G6 L- I
template< class _t> struct IsContainer : __IsContainer_Unwrap<std::remove_const_t<std::remove_reference_t<_t> > >{}; // 不能用`decay` 否则`T[N]`就退化为`T*`了;- z6 H" ]7 ^" C/ R* Y
: X4 h# w: n, _/ M2 L3 t+ T5 s: {! F- Q template< class _t> struct __IsPair_Unwrap : std::false_type{};% V4 Z! o% Z+ W1 v7 Q% z# l! x
template< class _t0, class _t1> struct __IsPair_Unwrap< std::pair<_t0,_t1> > : std::true_type{};* P$ w8 i; p- L R' g) X
template< class _T> struct IsPair : __IsPair_Unwrap< std::decay_t<_T> >{};
8 E5 z$ o3 ?9 n7 d; R
C1 E0 S" U; F" x/ | template< class _t> struct __IsStack_Unwrap : std::false_type{};: Y) B% S: c# |( C
template< class _t> struct __IsStack_Unwrap< std::stack<_t> > : std::true_type{};
" J% M0 \% K2 J# ]/ P. O9 J template< class _T> struct IsStack : __IsStack_Unwrap< std::decay_t<_T> >{};& m& `. [( D4 p
2 `, a1 H4 l7 P* ^; n9 V template< class _t> struct __IsQueue_Unwrap : std::false_type{};
7 z4 z" |! I) e) r* A template< class _t> struct __IsQueue_Unwrap< std::queue<_t> > : std::true_type{};% g; ^7 W+ f4 |3 V
template< class _T> struct IsQueue : __IsQueue_Unwrap< std::decay_t<_T> >{};
* ?+ C2 d! f8 M9 _' r8 X: ~; K
& u$ q- m( f& Y9 Q template< class _t> struct __IsDeque_Unwrap : std::false_type{};! n9 I+ n4 [( H) H8 x' o, B
template< class _t> struct __IsDeque_Unwrap< std::deque<_t> > : std::true_type{};4 M* ? I4 ?5 P6 u6 n+ f
template< class _T> struct IsDeque : __IsDeque_Unwrap< std::decay_t<_T> >{};
- L2 A7 J' F/ H" L R
+ g( z7 o6 N S& K' o template< class _T> std::string ToString( _T const&);
# [& |/ p- |& b% U* X7 b7 z4 t$ K+ {' Y
template< class _T, int _Check> struct __ToString_Category;
# Z/ V" H x4 X" V* a) S template< class _T> struct __ToString_Category<_T, 0>{ // Single
. i, G/ k! n1 d A6 P4 ?$ e, m7 P template< class _t> static std::string TOstring( _t const& _v){, M2 z1 d+ c0 `# N
std::ostringstream ANS; ANS.precision( std::cout.precision()); ANS.setf(std::cout.flags()); ANS<<_v;' V2 p& ]8 |4 a1 o0 z+ q
return ANS.str();- D+ l& y, X3 u) s
}2 X7 t: m, ]$ u$ a
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;}
7 z3 Y/ F9 m$ j: f( Y; B 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+ D9 G/ T# q, E$ m3 H static std::string TOstring( bool const& _b){ return (_b?"1":"0");}
3 z9 m D; N1 h( y static std::string TOstring( char const& _a){+ B8 T$ _& N$ g# A/ X
if(_a==0){ return "'\\0'";} // 否则因为她是*结束控制符* 会导致`ostream<<char(0)<<A;`后面的`A`不输出了;% f; k$ j5 Q( s3 w6 c7 ~, I+ Y- E
std::string ANS="'?'"; ANS[1]=_a; return ANS;; P& Y: z$ w, H, r2 P* j( i
}. a& k+ _- i" k9 Z
static std::string TOstring( char const* const& _s){ return std::string(_s);}/ `8 D1 |6 ~* T5 c% `2 T! a
static std::string TOstring( std::string const& _tt){ std::string ANS="\""; ANS+=_tt; ANS+='\"'; return ANS;}' L8 U g- o! K& [
};
, `& `0 \- D: [0 P L. i% H template< class _T> struct __ToString_Category<_T, 1>{ // Container* y- i9 w3 I) @3 u% X
template< class _t> static std::string TOstring( _t const& _v){
- E+ w/ @ O: w+ k5 X std::string ANS="["; bool first=1;0 G, r1 u, A- x; x5 Q# u
for( auto const& i : _v){ if( 0==first) ANS+=","; if( first) first=0; ANS+=ToString(i);}
8 b/ _' e/ f# \: ~0 R ANS+="]";* n3 Q6 u$ z2 ^& e$ ^0 T, }
return ANS;
3 R& U: Y2 g1 L% m- U }
- E5 P, Q3 o1 [ };
7 |, p' e. l. {6 }9 b template< class _T> struct __ToString_Category<_T, 2>{ // Pair: }' T+ J- g5 e7 \$ _
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;}
3 b* j, Y9 E; j4 m m& U* e };. Y% z0 k1 e7 x' X. F5 Q
template< class _T> struct __ToString_Category<_T, 3>{ // Stack
' M ?$ B5 ~" d; }" Y( ]* L 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;}
+ a. h& s: w- { };* y1 W* N6 W- h! n
template< class _T> struct __ToString_Category<_T, 4>{ // Queue
6 I& |4 F6 H7 T# a$ w- `9 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;}
% A8 L+ o7 ]5 G' W6 U };4 b2 { f7 z0 C5 v- F8 F) K5 D
template< class _T> struct __ToString_Category<_T, 5>{ // Deque. N8 l" Q- F3 Q. u# _* n4 ]
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;}
: x+ \3 W( I& y- d };
+ {# u2 J- p- N$ {
2 z8 {/ }* b6 ?/ j, y) k9 Z T2 W$ f& A 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)))))>{};
: h/ h* J" s5 @% e
6 P- b% F3 |( q: [6 `2 f d template< class _t> std::string ToString( _t const& _v){ return __ToString<_t>::TOstring(_v);}) E" i$ }, K' y) d
- n) q3 h9 H/ Z$ S template< class... _H_> std::string ToString_Items( _H_ const&...){ return "";}
" y- p" \6 T" l- ]7 K8 v+ s3 [ template< class _H_> std::string ToString_Items( _H_ const& _h){ return ToString(_h);}4 z9 J/ D/ Y% B, Q0 y' e; l
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;}; h5 B5 ~% |( w* V- k$ g7 X$ j4 I
}
7 P4 {: \% S7 u3 P( v+ n2 X3 r7 o: J
1) W0 I& f! `* q4 ~( S c
2* W& |1 b# ]8 l: K3 z: m" i3 a
39 p0 N: t* |; a6 Y
46 O0 z3 v0 ]9 r& r: h2 C+ R9 L
5
- h0 d+ K! h4 b7 X2 a6
2 ]/ J4 K4 Y+ t7
9 ]+ v0 C( Q0 P4 W( Y- [8 d8
/ U2 r: a( f+ R5 n) R) N6 i9
5 R. F @0 Y8 }( J10+ q4 ]! q ~/ n
11% E, ]6 c3 }# |5 B: w
12
: I5 _ B( J+ \, v2 c13
; w$ j) z9 r" F2 \) o/ J8 N2 c14
% i- o& F4 }% W1 [: P153 _ p) P7 H) J3 x/ J
16- Q% ~+ I) ]7 B+ d
17 w* z8 R% s2 F' P# h: x: j t
18
- b6 E" ?7 j! S" [( u2 K; b& `- R19
" u. q7 \- \; P. n20
+ _, S) f# z% W/ F21
5 r4 y: g D; I' A22
8 N$ A% ? K B N8 M6 r23
9 |+ {# t) p2 k$ C6 U _* y24
8 z. {$ A3 }0 E. e" m1 t' W8 Z25
" l4 y8 n8 d T% ~26
% K8 m6 n- N7 \+ F; f6 d. I# t8 G27
- E, h9 Z! ^2 ^0 L! X; q7 U! _28
! p; \& M2 L) d294 X: k) ~- E8 }9 t
30
! l9 V) I" `! e7 S2 u, C: u31
+ z5 c# |5 h# w) `32
S+ j! Z0 c3 o' y2 [33& m1 N) U+ S4 U+ {4 F5 \% A
34
! S% R( @" C( B35
8 T' v; Z1 b* l4 U368 G5 C& G# c1 G
377 {2 d3 R- U! N2 q# ?# L* U; a9 u
38" a; c% q/ Q" P: ?: l4 @! m
39
; u! i" w' {/ r' A# U5 v& m40; ?2 t+ {3 R& o+ @' }7 V0 d* g
41
+ n& c/ h( @0 n: C! y, e9 o5 k4 Q; Z42& N5 P! v- V& I, Y U
432 p1 f, P! S4 a
44
; F' Y+ w P2 f45
* ~* y. S! t' R) |. V; w3 M46
4 H3 `# P$ U9 H l2 I$ m6 V: I) P9 r47
# ~: J/ Y3 U2 o. ~48
0 v2 y2 |& A, `* J( n" }49$ l2 i. Z8 E" e
50) k K$ u0 B5 B$ G
51
+ J& T; F. [& V7 p$ z( i7 Z52# A0 G" |. E- u# x
53
@7 V, N3 L5 i9 `7 W0 P54) _/ n! y& {: Z5 r
55
" H V: W8 j0 w& R56
* ?1 l9 `4 Q1 t/ {) c57
" j7 K7 T/ p9 c$ L$ S58& D- a" q% }: e8 ]
59
: U% D; a2 b4 H" u5 P0 C; S60
7 c x# Q1 d8 d. b61) U" h* H$ r; Y3 N0 {
62
6 i$ a' H9 K) ?8 s0 F63
& ^2 i9 b5 {2 {/ k64% l' y0 n. k. H% C7 N2 b+ j. d
65
* k% ~( z7 x. z: v$ G4 A3 C M669 }) H/ W6 z8 p9 I( g
67
$ Y0 |- C, C1 [/ g: Y7 ]" W68
5 `( M$ p1 i1 N) Z3 B3 m- U, _8 H69
* l& A# { I! o& b70+ y; A+ X. ` K8 f
71
" L( J& z! E/ d7 n727 c, h) }) U* v$ i0 c
73
! J3 M4 I1 R! G/ i& |& x74
) z9 A7 F$ E; t0 b7 A6 n75( ?* M; r& U7 n) X6 O6 \7 n
760 ?* @. l; ?5 N' U# B8 |
77* O1 h- L2 s( e# _ o2 H* e0 {
78
5 _5 j) y& a9 ?0 T" `: `9 c0 E79; p. f0 X6 l/ @3 B
80
% x# U0 j: N1 W9 C. d% C) l812 R9 M3 s! }. i
82
6 _) z/ [$ H* X83: F& Q" t+ H$ {2 }1 z0 H# }
847 m/ f. ~( r; d. P
85- p6 ?) ]. h7 Q. Z
864 ~' M8 q3 H" S
性质: i8 j+ e- z6 w V
#TOstringITEMS_#
- k, P- k, j. Q' d这个宏 是为了: 对类进行输出时 可以直接_cout<< TOstringITEMS_(成员变量...);
5 m* }1 a" y8 h* [! S/ G6 w7 C你可能认为, 直接_cout<< ___Debug_::ToStringItems(...)不就行了?
3 p' u9 |# J( ^4 C. 错误, 因为在最终文件里 是看不见___Debug_的, 所以写成一个宏 在最终文件里 #define TOstringITEMS_ "";
5 q1 w& O/ u' W6 G! S& D0 G6 e. _5 }' K' r) T
笔记
6 x& @7 a4 n7 `+ n5 {% |#以前的debug.hpp#
: Q) U5 a( `" G
7 Z5 r; `4 W6 {: p2 A//{ omipusDebug.hpp
. D* C$ _: C# f- q, f3 j8 [#include <bits/stdc++.h>6 V2 \ w0 ~1 N% u
) C& { F9 q* K
#define TOstringITEMS_( ...) ___DEBUG_::ToString_Items( __VA_ARGS__)6 v$ }+ w4 w2 G. s2 H% I" R5 v
#define DE_( ...) std::cerr<< TOstringITEMS_( __VA_ARGS__)<< " "<< "{"<< "Line: "<< std::to_string(__LINE__)<< ", Var: ["<< (#__VA_ARGS__)<< "]"<< "}"<< "\n"
% ]! \' l. y* y) g( m) v5 X#define ASSERT_( _op, ...) if( !bool(_op)){ std::cerr<<"Assertion: ["<< #_op<< "] {Info: ["<< TOstringITEMS_( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< "); Line: "<< __LINE__<< "}"; std::exit(2267);}
* `+ G; @7 h9 f; z- p1 Y7 |#define ASSERTsystem_( _op, ...) if( !bool(_op)){ std::cerr<<"Assertion(System): ["<< #_op<< "] {Info: ["<< TOstringITEMS_( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< "); Line: "<< __LINE__<< "}"; std::exit(2267);}% \3 M4 f& Z; i! b
, y" H& w6 M' D3 t" N! Y9 r( Y* N5 \. Anamespace ___DEBUG_ {
9 @ R3 q+ k& r0 G. d- s: c template< class _t> struct __IsContainer_Unwrap : std::false_type{}; // 所谓`Container`是指 可以通过`for( auto i : S)`来进行遍历的;" [) o( T9 E3 `: X5 L
template< class _t> struct __IsContainer_Unwrap<std::vector<_t> > : std::true_type{};( b. a, d: Z& K! g* m- y& r
template< class _t> struct __IsContainer_Unwrap<std::set<_t> > : std::true_type{};" _1 ~9 z7 o$ v3 ]/ q w
template< class _t> struct __IsContainer_Unwrap<std::unordered_set<_t> > : std::true_type{}; g1 Q! T$ L4 P& P
template< class _t> struct __IsContainer_Unwrap<std::multiset<_t> > : std::true_type{}; z4 w {! }: \; F, a; E' x
template< class _t> struct __IsContainer_Unwrap<std::unordered_multiset<_t> > : std::true_type{};
$ q/ v- i8 \. S- |% J( c template< class _t0, class _t1> struct __IsContainer_Unwrap<std::map<_t0,_t1> > : std::true_type{};
- w6 ]8 O9 x: d- g6 R d3 ] template< class _t0, class _t1> struct __IsContainer_Unwrap<std::unordered_map<_t0,_t1> > : std::true_type{};
5 V. h+ r- q5 r* I) c3 ]! b% k template< class _t0, std::size_t _t1> struct __IsContainer_Unwrap< _t0[_t1] > : std::true_type{};1 W B! g( ~' l) t6 j6 _2 n. I `
template< std::size_t _t1> struct __IsContainer_Unwrap< char[_t1] > : std::false_type{}; // 特判, 字符串常量"..."不属于容器;
$ P8 X) z" ?! o9 W' ?8 { template< class _t, std::size_t _siz> struct __IsContainer_Unwrap<std::array<_t,_siz> > : std::true_type{};/ b& {4 ~; j3 Q8 n# w
template< class _t> struct IsContainer : __IsContainer_Unwrap<std::remove_const_t<std::remove_reference_t<_t> > >{}; // 不能用`decay` 否则`T[N]`就退化为`T*`了;
- e3 k6 \4 t* q5 u3 L6 {- n; a- y# P7 z. ]3 i7 n
template< class _t> struct __IsPair_Unwrap : std::false_type{};$ w4 w5 U2 f M5 h4 U# N
template< class _t0, class _t1> struct __IsPair_Unwrap< std::pair<_t0,_t1> > : std::true_type{};% i. @/ z! f2 s3 s
template< class _T> struct IsPair : __IsPair_Unwrap< std::decay_t<_T> >{};
) z8 {) ?, i! ]! x! ?- e" `
2 L; \" o- T: t! K2 P8 c/ ^ template< class _t> struct __IsStack_Unwrap : std::false_type{};' R( x+ p# p; Q& n. c, p; _9 o! `
template< class _t> struct __IsStack_Unwrap< std::stack<_t> > : std::true_type{};
% g1 v: n/ Y) ?9 X3 P template< class _T> struct IsStack : __IsStack_Unwrap< std::decay_t<_T> >{};
1 J, [+ ?9 Z+ i8 a; b' w* t$ K3 {4 s. u: z+ H7 |8 v I% d
template< class _t> struct __IsQueue_Unwrap : std::false_type{};8 [5 s# U" M9 d& v; I% N: [ A
template< class _t> struct __IsQueue_Unwrap< std::queue<_t> > : std::true_type{};9 H O: h2 V$ ?# C* a" J* k
template< class _T> struct IsQueue : __IsQueue_Unwrap< std::decay_t<_T> >{};
+ m+ g. I5 k+ n- \
! L- X; n) U3 }3 [3 d0 m0 b/ Y template< class _t> struct __IsDeque_Unwrap : std::false_type{};
7 b u1 _# Y6 T/ q) ~' p! K: j* y template< class _t> struct __IsDeque_Unwrap< std::deque<_t> > : std::true_type{};' F6 H F) t" }5 }0 D1 N& F
template< class _T> struct IsDeque : __IsDeque_Unwrap< std::decay_t<_T> >{};- r* Q2 M2 B% B* h( e, ~
5 x3 ]% Q. T6 e& { k7 {. s template< class _T> std::string ToString( _T const&);
0 f7 R0 `/ j; P' _# @" Y
. h; Y1 K' z# i8 r# I template< class _T, int _Check> struct __ToString_Category;
8 ~; D: e7 ^$ w2 ` template< class _T> struct __ToString_Category<_T, 0>{ // Single# r8 T2 e& r& ^$ T: v+ i
template< class _t> static std::string TOstring( _t const& _v){% Y. C* {3 G! l+ M5 m% V% S) U A
std::ostringstream ANS; ANS.precision( std::cout.precision()); ANS.setf(std::cout.flags()); ANS<<_v;0 t2 p8 X3 m" t- n6 t( a
return ANS.str();" D( _0 f6 [; W2 l
}
: }' e3 }: `* M6 I& i 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;}/ l. M0 e9 z; L4 I
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;}
2 l; e& ^2 E9 `+ x: f6 ]/ _) U static std::string TOstring( bool const& _b){ return (_b?"1":"0");}
1 a1 g$ ^8 @: g0 X; a, b3 U3 Q static std::string TOstring( char const& _a){0 x8 ?: {3 `9 _ C
std::string ANS="'?'";& _8 S9 a- B; A& J8 N; k' \2 g. W% s4 @
ANS.replace( 1, 1, std::to_string(_a));: W5 P9 d3 [9 l1 m9 u7 b# p
return ANS;- x. _( U' m, t: T1 S3 V/ u
}
( p" t! F. z6 C E" D% q static std::string TOstring( char const* const& _s){ return TOstring(std::string(_s));}) \( q; N# B& y& y1 h
static std::string TOstring( std::string const& _s){ std::string ANS="\""; ANS+=_s; ANS+='\"'; return ANS;}/ {/ G& c* C/ T0 t: [& `& D. V- [
};
& Z# Q& ^: E8 ?( }- \ template< class _T> struct __ToString_Category<_T, 1>{ // Container) d1 f5 \- `5 e0 b
template< class _t> static std::string TOstring( _t const& _v){" M4 t! q& z) ?
std::string ANS="["; bool first=1; for( auto const& i : _v){ if( 0==first) ANS+=","; if( first) first=0; ANS+=ToString(i);} ANS+="]";
" |/ P' T2 q# [# Y" m return ANS;1 p: I' ~ C0 e' }
}
1 |$ N6 i. U( L: o };' s: r- H' l7 T' b. ?
template< class _T> struct __ToString_Category<_T, 2>{ // Pair0 p( z: ^: K' c% H2 u5 \, y6 _6 V [
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;}
9 K* W) _* c! G, j8 S; d/ B& R8 ] };
8 Y$ @5 x3 X. \ template< class _T> struct __ToString_Category<_T, 3>{ // Stack
9 [: [/ Z* l% ~3 y! P0 c 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;}2 @( g: ]! v. V+ u( X4 Q
};
/ d& e0 I! n0 M) V, L; W: d template< class _T> struct __ToString_Category<_T, 4>{ // Queue
" g8 U* T3 y' l% N- }, [ 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;}- _' A5 a: P% _( L0 ^
};/ @. c- d# S i+ _9 b0 j6 {4 L
template< class _T> struct __ToString_Category<_T, 5>{ // Deque
. |( w6 k1 w6 E4 [" n1 l5 c 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;}! ~, b2 b* M4 w
};8 P6 U% X( e1 G+ e# Q F
1 l' r' D0 |& A: T template< class _t> struct __ToString : __ToString_Category<_t, (IsContainer<_t>::value ? 1:(IsPair<_t>::value ? 2:(IsStack<_t>::value ? 3:(IsQueue<_t>::value ? 4:(IsDeque<_t>::value ? 5:0)))))>{};
; @& I* Y' N4 X) B2 J0 B3 y. V$ N& M! I
template< class _t> std::string ToString( _t const& _v){ return __ToString<_t>::TOstring(_v);}
; z& |( x/ ^ d$ ~
" w6 X }/ G/ d: z' I4 N template< class... _H_> std::string ToString_Items( _H_ const&...){ return "";}
3 P* Z6 @: k9 M template< class _H_> std::string ToString_Items( _H_ const& _h){ return ToString(_h);}) _. M/ m2 q: ^% D
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 M- f% P" J- m8 L& l}
; s" v2 j y" L4 ^3 m/ M: V. `//} omipusDebug.hpp
4 x' d* E& L$ r6 m$ \/ C1
% k7 U" p$ K8 o6 t1 Q0 e2
% L& s* l. U& m7 J4 o3# A+ |* q2 i2 Q% ?+ k' c
48 }4 l; E- v0 \* \
5' x4 X$ w+ b- l
6& s& L6 y3 _5 F/ J2 O# _
72 o4 Y- p. S* U+ G. x
84 e& ?: e4 c8 @5 A, `- }3 v$ t* o
98 u* }# ~6 d8 w* W0 O( |
10
& n" @2 T3 D+ s6 l4 o118 i8 x" O* ^5 m$ }
12' C& `2 N* q, [) g0 \6 P* F+ f/ E
13
3 a8 V1 e0 L, x( O6 u140 r3 _' n( [- f! n1 U
158 @; a( M' T; f
169 _7 v1 Z$ q: q- t
17
?' B" J! n4 T' A; j% `18, r4 \, f; I. w- i
19
& g& L0 }7 a9 o# z# s3 [, c$ k l7 i20
* H, ~! G6 `7 O: N: R6 j% D211 z& k( H, A: {2 V t
22
' _8 ]9 p( _" T; `+ d$ }- ^23
3 l' T8 @' Q* ^7 k# f1 Q24$ t- g4 U( e/ Z/ q
25: Y6 D7 K% U; ~
26* E" I: u) u# W! r
275 J2 m4 l5 [7 Z. ?7 E& Y
284 `' p' N. O4 X% y
290 X7 k' G% \" o. V* o5 b
30: |( H5 N6 d1 @2 F0 |! s
31
, H: F, f3 b- E' h32- M' p; s# h9 o, U$ u- Y4 j
33
8 C; q/ G l3 N344 ?3 L" N4 A* X9 n, Y/ b. K6 \6 ]8 r
35
/ {) J' Z# C: ? Z7 a q2 m36
7 E8 ^( D5 C" ^. Z37- n6 i" _. Y* E, t
38
- N& O0 P4 q9 N$ C2 h0 P* W39
+ j/ b6 j% Q6 a40
' g1 T! c. \6 M$ l1 J& I, y41
2 b; |; U! ]) r6 v L B42 X+ E% C2 ^: L+ N* w! F
43( p& t3 Z4 O& b( l8 h; b! ]8 W
44( E6 h+ W! z6 [! a7 }3 S
45
# z; \# S& A! v* ?" G465 X1 N, a2 W* Y! _ Q/ F
47! U* ~. N3 |* v3 U' ]; E
484 Q6 P, t" G& r' n4 ]
49/ u- h- o8 {" z3 k f
50. T+ m( {) |, @5 J6 M0 J; c
51
/ m: ?, F k$ @# M+ T. G: P; g+ n52
8 p1 \4 o3 @( W7 V1 O$ u53" v6 l4 F2 h3 r3 O4 ^
54
3 [+ U( P+ A' j+ y55
+ y Q# U ` E56
{, o5 j z1 D& N57# M( |0 g2 q7 \* o8 x' S
58: p' C1 D5 P* W' r
59; [. b# T, ?$ e3 j. A# O+ i
60
0 A8 H! J2 r; c7 `0 S1 d! a2 F61
$ o$ C& j, Z, T9 Z& W62) Z$ n5 N ^0 B2 d
63
/ r/ o0 k, e0 D: j+ L646 r1 c8 g) Z6 r4 e1 M* ]' l
654 L+ d" f# R' U0 H9 q0 \- p/ H& \
66
; p5 y1 A' `, a8 j/ W- @67
. D& P. \! z. K; z5 B684 N' k% N7 ]6 k
691 x# h. L+ g! {, }/ x- `
70
& @. h$ @7 O' q$ _/ r- N' H71% u+ y- d( @5 }- X; `* s& H& ]
725 _+ S: R5 L: u& Q5 `3 K1 t; }
73; W) Q' {, [7 m" R5 n$ y
74
$ [( S" R6 j: o75% a0 P* G, w: z
76
5 ]( g$ g+ u, Z) V8 A/ W i77
( e% D$ [3 j q7 {. |78; |3 }8 L$ H: c: F+ j1 x' a/ T4 F9 K
79
! N. a$ l+ Q! K: g ]" K; t803 @# C# W8 x# }: s8 [
817 c1 e) B) }! O5 r4 L' R, Y2 q$ M2 Z
82
# W% C9 _+ y( @! B! q, o' c6 h83+ t* n" I2 c( U6 y* I
84
2 d5 E l! x1 f1 |# v4 R# v85
; l \& t( \' D. Z; S算法競賽配置" b8 J8 M; I! U' ?( r7 j
QT_Creator
2 f6 X6 S$ h; [# K1 @創建一個控制臺應用, 然後在Pro文件裏 添加CONFIG += c++17 (原來是c++11 修改成17);, M, ]0 J/ Y( X
# T% `1 W3 [7 b; d0 @% o1 J9 j對拍文件# u0 E- t& D: _. c$ f; P
`compare.cpp`# J: g5 s( s3 W1 h! ^; @1 |' Z
) W& O" r6 a+ s/ N( L6 E! {
int main(){
3 @9 v H2 L/ _; p% w& z% K8 I# ? vector< const char *> Init{"build.bat generate_data",0 g8 n9 y+ T6 R2 v j
"build.bat supimo",
* y1 ^2 j4 ]( i% C1 b4 h5 ` "build.bat correct"};
9 Y3 f# H( l \ for( auto order : Init){
+ `3 o. i7 C: _( Y+ k0 s auto errorCode = system( order);
1 G! M/ f6 w# {# F: M8 E if( errorCode != 0){ EXIT_( order, errorCode);}
" p% p; t+ ?' F7 F/ M, ]$ H }
% W5 V s* A6 V( _* B% E K3 b
# q, `( ?& ^" D0 L* y3 d while( true){
5 X* H7 L9 S4 J' A. x static const char * Ords[] = {"generate_data.exe > data.in",
' N- X! N+ q" {/ V$ a6 j3 D6 L3 \! W "supimo.exe < data.in > supimoOutput.txt",1 K# P R0 l. G; q% U
"correct.exe < data.in > correctOutput.txt",% \/ i' H+ w- K% u% |) h) b2 d
"fc supimoOutput.txt correctOutput.txt"};
- ^" N2 x* D1 n$ K% D+ X. ~ for( auto order : Ords){3 ^0 X3 p) P3 S/ e; K' {5 R
auto errorCode = system( order);
1 c0 P- ~3 t3 Z$ i if( errorCode != 0){ EXIT_( order, errorCode);}
: s/ \ {) }/ k' g' t }
5 C, P2 [+ q2 { cout<< "SUCC"<< endl;0 n" g9 _ r6 r. A& V3 h
}- H" M3 c q Q0 X
3 @" K9 g( s+ N/ W. n( F
return 0;
" s, I5 A9 k9 O$ d. L0 K/ x}4 H j" R, K) J% L/ }% H
1; y2 l: Z5 J9 \: S) m
2
# [; n$ x( p! Z31 K5 M6 C: e6 y5 l/ w7 w' |, c
4
' p+ p; q+ j; J" P9 B2 O53 i0 {4 J. v! J
6
, G+ ?$ `9 p. A' N. Q7
3 Y: P0 n" a- h4 J# Q8
# _( w1 D' R! p' {: _) \96 h4 p5 Z% |$ v- v% H) F8 y+ `
10
8 r4 T/ u1 U( c2 F) s) E8 W, B11
2 _0 X+ \, p% E12
( @0 B7 Z* z: H! x; |130 y* y. j2 y7 h/ E3 B, l1 a
14& F- G2 P7 b. b1 M+ N) C
15+ {" e- R9 D! e+ c
163 O$ @# c1 o6 \/ e3 C- a6 B$ u
17
/ A2 \: j' }+ B0 A: |) m18
! w3 ]5 s8 W+ \( R3 i1 E19
* |/ o& g7 j. u5 N202 b& o# X9 J( ~; v' t/ e
213 F) a: s% C6 u3 @! G
221 `0 k! J- A! O1 H, G! A" b% t( B
23
! \1 p& r2 \# G `9 U+ f2 h24
7 F3 R* i3 O* f: K. V25
/ K( L# \+ ?) W% h+ [$ S: o2 b, WBat代碼
7 i2 z7 l' d( c$ qbuild.bat& F* z2 A( n8 n2 I! n e8 J
@echo off
+ R @) N; U9 u1 l" mdel %1.exe
% @6 I2 {/ _9 N- e. z' t$ og++.exe %1.cpp -o %1.exe -std=c++17 -O2 -Wall -Wl,--stack=268435456 -D"__ISsupimoENVIR_"( L% S3 Z. I2 e5 V
0 u. l9 j( H6 y" }" F6 Y# P6 O@DELI; ^/ y4 u* ?/ u- s5 H/ w+ M& P- [
; D, [3 W' R, G# {, a
run.bat
+ r$ f% R, J$ n+ j" E0 L# U@echo off: @8 O# J3 N; f! F. l+ q8 B
%1.exe < input.txt# q- k( U' ~6 f3 O0 t* A: X! g- h
: K6 G, P3 z# ^: ^' O
@DELI;
5 C0 A7 g$ U+ H; t% P' G: f
/ r( g1 r- R+ Y4 \% K7 ~7 Y* ubuild_and_run.bat" i" K( W. `1 i" V' n
@echo off+ P& t8 e: l+ f+ a" s5 T, O
call build.bat %16 ]( C1 h8 u( L5 B! V5 E. G+ g
call run.bat %1 %2$ k' f) a6 z4 ?- [/ z5 F$ x$ Q
1
3 t7 Z. i, z4 ?0 b7 v( \2. J$ c5 @1 \3 l- t
3
; a! y; m& i. u1 L4& b5 c$ R8 t* z3 b& f1 g& F
5; w: @4 z: m' J6 X6 e. }* S2 j
6 f; K& |3 s m2 M7 F
7% x( _0 Q2 n# x
8( l( v) M' O( W# ^, U6 J
94 _+ O4 G2 r! M/ Q9 u
10
/ R4 n' ~! s0 p& K9 Q11
. @& [) L% ?* r+ E12
( T; ^/ }$ \3 r: w! m" }13
" ]9 S* [6 T3 b. Q. k3 F145 l# F9 [7 O! J" a: S
15 P0 o( J* ^4 q$ _
16, z: u3 F6 [' u
17' h1 I* L% {- u& C0 n+ S/ z# {
源文件
' ?/ @" b& I- N6 E1 Z#include <bits/stdc++.h> f. c. G% H/ Y9 d1 x+ Y0 Z
using namespace ::std;$ x5 z( x; @0 J7 B% c6 P& h
* H2 I' @$ ?' T% n
//{ ___SUPIMO8 A. X& d1 ^. ?2 E; B
namespace ___SUPIMO{. m! W2 I! p) ^2 V, O- _& p8 ?$ E* ^
//{ Macro
. }0 j0 Q3 E1 C; c n' S9 S* F#define ASSERT_CUSTOM_( _op, ...) if( !bool(_op)){ std::cout<<"Assertion_Failed(Custom):["<< #_op<< "], Hint:["<< ___SUPIMO::Debug_::__ToString_items( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< ")\n"; EXIT_;}
( x9 v2 |5 ~7 i! u# c5 b" g8 u#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 i, e! ?* z2 X8 O#define ASSERT_MSG_( _msg)
/ {9 Y6 }6 l; F) h1 l( |1 h( r3 c0 o#define TODO_RunTime_( _msg) ASSERT_SYSTEM_( 0, "@TODO: " _msg)7 l; X* }: c/ ~3 G5 C
#define EXIT_ std::cout<< "EXIT: Line("<< __LINE__<< ")"; std::exit(1);
: Y9 p6 @% z v0 x* f#define EXIT_COUNTER_( _max) { static int cont = 0; ++ cont; if( cont == _max){ string str = "EXIT_COUNTER(" + to_string(_max) + ")"; DE_(_str); EXIT_;}}
$ u0 s; v8 e; A; ^/ P#define FOR_( _i, _l, _r) for( int _i=int(_l); _i<=int(_r); ++_i)
' r u$ f+ M2 T: s" \. Y* w#define FOR_R_( _i, _l, _r) for( int _i=int(_l); _i>=int(_r); --_i)* c2 j9 F- c T% P" s a
#define DE_( ...) if( ___SUPIMO::Debug_::___IsInDebug){ std::cout<< ___SUPIMO::Debug_::__ToString_items( __VA_ARGS__)<< " {Line: "<< __LINE__<< ", Msg: ["<< #__VA_ARGS__<< "]}\n";}% T" v# w9 l* J. B8 b! C$ _
#define NOTE_( _str)) y. A% Q2 |1 W9 T( G$ y4 D
//} Macro
; N9 a: [6 E* p3 E; n! |! j r1 Q `; f: N' Q5 W/ D1 ]2 p
namespace Debug_{
, t/ o; N; `, ?7 @) g static constexpr bool ___IsInDebug = 1;8 g+ s, t7 g @+ X! U" L
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> &);; t0 d) @3 d. i5 `& a
string __ToString_items(){ return "";} template< class _H, class... _T> string __ToString_items( const _H & _h, const _T & ... _t){ string ANS; ANS+=__ToString( _h); if( sizeof...( _t) > 0){ ANS+=", ";} ANS+=__ToString_items( _t...); return ANS;}7 k6 W- n( K, T) s) i2 C
} // namespace Debug
3 ?2 S3 z8 x. k" @4 z1 L- y. I
: S2 [( y( R1 a7 q' N//{ Type4 l2 x$ Y/ P/ D: [+ n. E' Z: p6 a
template< class _T_> using Heap_small_ = std::priority_queue< _T_, std::vector<_T_>, std::greater<_T_> >;! N- |- C. ?! ] f
" z/ f6 R4 }9 K& E
struct Double{/ F# [8 A9 U$ g4 o
using __Type = long double; __Type Value; static constexpr __Type __epsilon = 1e-12;
+ j9 u, \8 k2 h; x& `0 ]' \0 l 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;}4 ?5 J9 I# }) I( R7 n
bool operator==( const Double & _b)const{ return (Value<_b.Value? _b.Value-Value : Value-_b.Value)<=__epsilon;} bool operator!=( const Double & _b)const{ return (0==(*this==_b));} bool operator<( const Double & _a)const{ if(*this==_a){return 0;} return Value<_a.Value;} bool operator<=( const Double & _a)const{ if(*this==_a){return 1;} return Value<_a.Value;} bool operator>( const Double & _a)const{ return !(*this<=_a);} bool operator>=( const Double & _a)const{ return !(*this<_a);}
- W6 g7 m% Q3 d2 _) ?7 b 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;}
! G. J4 \2 ]9 a( ~8 T}; // class Double
" J5 U9 s3 Y' y9 R
, P: l& l* P+ x0 x _template< class _ModType_, __int128 _Mod> struct Modular{6 B+ M/ S Y! w) ]" A; b: A
ASSERT_MSG_( "_ModType_必须是{int/int64_t/__int128}");7 y& @% N4 ]# P' G8 S
using __UnsignedModType_ = std::conditional_t< std::is_same_v<_ModType_,__int128>, unsigned __int128, std::make_unsigned_t<_ModType_> >;
; Z' a( ~0 _! d. p inline static conditional_t< _ModType_(_Mod)<=0, __UnsignedModType_, std::add_const_t< __UnsignedModType_> > __Modular = _Mod; __UnsignedModType_ Value;
; l6 `- ]( B8 r2 [ ]& s Modular():Value(0){} template<class _T> Modular( _T _v){ _v %= (_T)__Modular; if( _v<0){ _v+=__Modular;} Value = _v;}4 L5 Q6 b7 g3 k2 _& g+ F& |
inline static void Set_mod( _ModType_ _mod){ static_assert( ! std::is_const_v<decltype(__Modular)>); ASSERT_SYSTEM_(_mod > 0); __Modular = _mod;}
( }/ ?+ H# q8 a3 @1 r& f% X 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;}
6 o1 g4 D6 z$ k, s, M/ S}; // class Modular
( l+ j9 F3 T* V, w" G, c5 P//} Type) i: P/ A! f/ R# q, E3 B* [7 F& h: m
5 P1 ?: \2 R3 Y2 ?7 |; p: Hnamespace Integer_{
1 K* u4 n9 [1 w+ L) L; Q 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;}
- E6 R& b T1 e7 y4 x5 j 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;}" q& d+ C/ n$ c7 s8 r) S
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;}' c8 M( L. R$ W+ b( h5 K
template< class _TypeRadix_, class _TypeNum_> struct Radix{ // `TypeRadix: 每个进制的类型; TypeNum: 所能表示的最大十进制数的类型`;' T p' N I* H. ~' C
std::vector<_TypeRadix_> __Radix; // 比如`Radix=[2,4,3]`, 那么所有的数为`([0-2), [0-4), [0-3))` 即表示的十进制数范围为`[0, 2*4*3)`; (Radix累乘值的大小 就决定了`TypeNum`);5 w" D+ Z/ R9 R& Y0 ~1 x
std::vector<_TypeNum_> __SuffixProduct; // `SuffixProduct[i] = Radix[i]*Radix[i+1]*...`;
" E" g( N& \3 r, 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]);}}- S7 u5 J& l* F/ m. S0 i; z4 G
_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;}! f1 \! r. Y ~4 z" V
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;}
; q% C& {3 @$ E6 I1 s& T int GetBit( _TypeNum_ _num, int _ind){ NOTE_("`ind==0`是最高位"); ASSERT_SYSTEM_( _ind>=0 && _ind<int(__Radix.size())); return _num / __SuffixProduct[_ind+1] % __Radix[_ind];}1 ^, @9 e/ k* E1 _0 o) Q9 M, Z
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];}
7 C$ [- ^2 k, C+ K! `+ ]0 T( V };
) L" W' c5 Q& j namespace Binary_{
8 D2 Q: f+ G, v9 B- y/ O 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;}
5 S# O' P3 U$ E% ?) ?8 h9 Q 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;}. L9 \6 B F- y9 m
template< class _T> void SetBit( _T & _num, int _ind, bool _v){ if( _v){ _num |= ((_T)1 << _ind);} else{ _num &= (~( (_T)1 << _ind));}}3 }) R% l; m& j) y m
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);}1 n* O0 g; R2 H8 p
template< class _T_> int Get_lowBit( _T_); template<> int Get_lowBit<int>( int _a){ if( _a==0){ return -1;} return __builtin_ctz(_a);} template<> int Get_lowBit<int64_t>( int64_t _a){ if( _a==0){ return -1;} return __builtin_ctzll(_a);}
5 ]+ O6 ?6 e! F! m# D% s6 m 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);}$ L' z% S4 I* M' X. h, Y8 L& O) \. t
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);}3 v/ t. u% Z) V6 @! X! e
// #枚举二进制子集#: `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]` 一定*严格递减*);0 D. {! e8 N3 ]. S! w2 F a: z7 ~5 s
} // namespace Binary% v3 x& t5 O/ W+ `3 {- e6 @8 G2 K6 C
} // namespace Integer& p6 n1 R8 x+ j
1 M# J; t: U2 M% R6 Xnamespace String_{! V2 G. t; ~! x7 V$ c; [: n
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);}
9 T( `, q+ _ z( m7 w+ i/ N/ ~1 K0 K+ G 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;}}
" w" |9 N$ g' d4 G/ z: m) c I 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;}
. w4 V* v* c$ L! F1 O% i} // namespace String
9 ]) J7 c. }; m# E+ R5 _
5 E6 F( ~/ F0 E4 b7 @namespace Random_{8 b% O6 e, b9 N y p1 c/ Q
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());% n- ?; m( P2 w, I3 U |: B
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);}( a d# G$ z$ }1 W2 `; A& V- d) h9 m- B
} // namespace Random
3 {8 U3 t8 C) h+ s+ [) }
# F! v# ?, i5 H$ q8 {$ _) A; Q `namespace Object_{1 q) d: _4 D W& A
const Double Pi = std::acos((long double)-1);
6 ^9 a& k! B9 l- o* R 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;};; v: X. q) Z( u6 b4 U
template< class _T_> constexpr std::decay_t<_T_> Int_0x80 = __Int_0x80<std::decay_t<_T_> >::Data;
% q4 @4 h- i1 a& Z' F! t9 H 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;};
6 U# f2 D) _3 \" ~, m& ~! S template< class _T_> constexpr std::decay_t<_T_> Int_0x7F = __Int_0x7F<std::decay_t<_T_> >::Data;7 m! j e0 N0 B) H
} // namespace Object
1 @4 Q! H* H9 V4 r- S
! @! Y3 i( g! g9 N& ynamespace Function_{
# a# a) L% ~: Y& j5 _ 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;}
7 U M, I: q+ U, b* P8 x. f 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);}6 K3 ^6 J3 t0 Q, I: H1 n
template< class _T> bool IsInInterval( _T _c, _T _l, _T _r){ return (_c>=_l && _c<=_r);}0 u5 Y6 f: F+ M! ]
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;}! j5 R- l' R. F( \# R9 Y
} // namespace Function
' A/ [- ^+ C' x2 Z: H: ^- v+ |7 j8 D0 x2 y
} // namespace ___SUPIMO
! g2 G3 f; s) Q5 G3 _/ R9 s# \3 A% W, c$ E( L( v
namespace std {2 x3 V7 I; ?: `+ t
template<> struct numeric_limits<___SUPIMO::Double> : public numeric_limits<___SUPIMO::Double::__Type>{};
9 b* l. r; I" m8 f template<> struct __is_floating_point_helper<___SUPIMO::Double> : public true_type{};
4 T. Y3 }6 O3 ]1 B" l5 A2 t template<> struct make_unsigned<__int128>{ using type = unsigned __int128;};
$ d$ E. `) ^$ j$ Y ___SUPIMO::Double abs( ___SUPIMO::Double const& _d){ return (_d>=0 ? _d:-_d);}# L) h# s3 b5 J0 y) `
}
+ j! ^, o$ C) Q/ ]$ u//} ___SUPIMO7 F0 \) C j- ?9 T8 u/ x0 @& C& ]
( |# U& V) o6 C1 [, b6 n7 f
using namespace ::___SUPIMO;. y, j7 B1 k8 _1 k9 c4 B+ ?/ e8 u, l
) q4 \4 S" f8 nvoid ___Solve_oneTest(){' _" w, g: A0 B5 c+ B
5 c' K, r9 k6 f) T
}
/ p& }# y) m$ |$ @1 \7 Rint main(){* \- w" l; [' {4 Z3 }( V7 l1 X {
std::ios::sync_with_stdio(0); std::cin.tie(0); std::cout.setf( std::ios::fixed); std::cout.precision( 9);7 ]* B/ V- T/ F5 T L" E
# W) ~# C& S6 ?! q& T: g8 D
auto ___Work = [](){ // 必须严格与*题目*的录入格式对应;
& |6 R0 u; O9 h1 } constexpr int8_t mode = 0;. s- T& O+ u6 p3 ?
int testsCount;
9 Z& g6 V: p9 z3 t0 g5 T$ U if( mode == 0){ testsCount = 1;} else if( mode == 1){ cin>> testsCount;} else if( mode == 2){ testsCount = 1e9;}
. |+ w" }/ o1 K5 ]8 ?( a, b5 T+ h5 Y7 o for( int id = 0; id < testsCount; ++id){ H. O! H: f4 g8 c p
if( id == 0){ // Global_Initialize
3 h: j/ h( q& p! f, B9 P; g9 ^, l1 @' p, o, V- ]
}. D6 G: T! _, f* V3 y7 ?
___Solve_oneTest();
' u4 \2 j7 a5 x: Z# Z }
2 \/ e' _$ q0 ]( l };- E; @- ?5 ?% `* Z2 e
if( ___SUPIMO::Debug_::___IsInDebug){
1 ?" q2 l+ L! m: ~6 A# [0 w8 p for( int id = 0; id < 100000008; ++id){! R6 E$ E$ L* X- `# j4 y
string flag; cin>> flag; if( flag == "___INPUT_-1"){ break;} ASSERT_SYSTEM_( flag == (string("___INPUT_")+char('0'+id)), flag);
2 S5 t; v+ x+ W) h' d& a- A ___SUPIMO::Function_::ClockSplit();
6 W2 u9 s4 m* c6 g" T std::cout<< flag<< ":\n";
4 R% z: z# v& e8 W; C ___Work();
! c' i* d. [. c std::cout<< "\nTimeElapsed: "<< ___SUPIMO::Function_::ClockSplit()<< "\n\n";3 {; S( ^ G8 O
}
/ p- n' |. U4 |5 E( ] }
' f: t) \; Z. _* j. y& K else{ ___Work();}9 ]$ W; C9 T" }3 }
( y+ A( ?; j% |: ]
return 0;1 D* {5 l# r9 b7 f0 o2 o
} // main: m0 y' u5 o3 q* \" w6 C3 o+ g7 I
' C4 c9 E' D8 E. f1 Fnamespace ___SUPIMO {" w' Y' s9 e# K5 d8 E
namespace Debug_ {
) L# Y9 g4 W5 J9 E" m template< class _T> string __ToString( _T const& _v){ ostringstream ANS; ANS.precision(cout.precision()); ANS.setf(cout.flags()); ANS<<_v; return ANS.str();}* y4 v5 F7 w% f, O& E' h$ M
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+")";}
( b) V. J! v1 I! t+ i' f) _ 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+")";}
: l7 q! a" \# R0 ]9 v) z string __ToString( bool _b){ return (_b?"true":"false");}
# d/ j5 Y+ t# ] string __ToString( char _t){ string ANS="'?'"; ANS[1]=_t; return ANS;}
, ?1 C9 U! E8 M9 }+ E) ?# k string __ToString( char const* _s){ return string(_s);}3 ~$ d; V! Y: j8 N9 g5 p8 H4 T
string __ToString( string const& _t){ string ANS="\""; ANS+=_t; ANS+='\"'; return ANS;}
" d- {/ ~ q" H, m; F+ a 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;}- i, M# y4 ~7 Q4 ?
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;}
8 R: f" g! p' r* H$ t* Y1 C6 S' v& L 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;}6 D4 j1 D6 K" I) }4 Z; 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;}, _9 V$ S( d+ o; L/ J7 a
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;}
$ R+ M! ]; J' l. b; m template< class _Key, class _Val> string __ToString( const map< _Key, _Val> & _v){ string ANS; ANS+="Map["; bool first=1; for( const auto & i : _v){ if( 0==first) ANS+=","; if( first) first=0; ANS+="("; ANS+=__ToString( i.first); ANS+=":"; ANS+=__ToString(i.second); ANS+=")";} ANS+="]"; return ANS;}
( M" a4 J4 ]5 G S8 R: `; l 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;}
# l4 Z# Z& M; d( _% H! y5 y: E1 I 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;}% _# l6 E) u+ P
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;}
) k# X7 z7 c; 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;}
9 j P( w U8 o& d0 a1 y. h 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;}
. [, ~; ]# H5 U/ g; 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;} P4 g2 r. A$ b8 z7 W; K3 E
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;}
: L# q* P* h* @; n/ v+ c }
* F% }9 G7 Z4 p# [* D}7 g s. C$ v0 b" z- E. ?- l# v
1
( u; V) w' T- `1 H* a2 E( H( m1 U8 I
3! S* u- s. B+ k" A' y
4
2 x! J$ N5 _9 K F P5
- U; k- w c% b; _6* r: Z- z! q! W3 @+ O% b
7
; ~9 e( a0 I/ k84 w5 I/ w% n' z, L% G# c' Y
90 u: C8 V9 J; M$ ^% j f
10
8 @: J+ }4 P5 ^ i$ z& F" k11& K K9 y3 h6 p' y
12& E2 T: A) ?: z5 Z5 J" O, { X
13, r5 G9 F, N6 ]+ z1 t( Q T
14' j* _0 r( z1 e6 c5 j
15
' k7 v) }) |- N9 z* q9 g" r16, s% a+ V5 }7 A4 Z# {. F; g& O3 a
17
* H( |* L5 i0 F3 l9 @1 v& }( ]18
- Y$ j9 ]; D9 [, ^& R3 }, L% g192 ?0 E: l5 N0 C$ e: U. z8 \+ y+ _% |
20! N7 H4 {# ~8 `& n2 \
21
% V/ W1 d2 v1 V: _$ T2 n- x* Q" V1 {22; }2 u8 K- ]" r# S
23/ R- h1 L8 `% ?, ^
24. s/ @, } q+ f0 q
25
. \( z# j2 J3 h% t+ B263 V1 J1 O% X' n
27+ K+ ]& C4 h( H
28% H S2 F+ n1 [3 m: p
29, }; i- m2 _ o4 A' @# h
30
% F" w. O2 b% ?, S/ J" H! L31 C1 H# C; x* x8 a/ Z+ c q
32
, v+ M. f) B7 C" g4 b33: o3 H, N, g& _
34
" n/ @! o4 y2 H5 \35
! c+ ` L6 k6 T5 ^, Y36' p, \/ b* X6 N# \' B! ?9 z
37
, t% v$ q3 i, \' U1 h& [5 q388 R# ]8 V$ E/ ?$ J, V; C; [# a
39
8 a1 |6 g t+ G1 J5 b& ]40
9 q+ d U& z+ ~5 ~% v41
0 d6 s( f* o; _0 p42
0 e+ U! C9 M' w" t- Y43
6 J+ P/ w. U% Z1 H6 a4 q( o44
' b6 _0 R' k; }! ^' _45# t- j) C! N8 V# U; E9 W8 H
46
/ h8 c) q6 f4 M6 i47$ r/ }# n& H+ d2 O9 [( w
48- ~/ K9 f0 L. a& ]! Q
49
1 C4 ^' N- z1 W: x& s50
$ b B- }) U* w1 T3 S, C, ~; k- |515 l# p$ D9 p; T# }9 \
52: M- m4 ~1 c; [8 a5 F! d6 m$ l
53
# N/ [$ F3 y* ], ~' B" h' y0 A/ D54
) E' \0 m4 _; ^6 O8 U55
0 r) w. t5 m" h. J/ r56
9 w B; x$ Z" H# F) e, Y57
6 P( t8 A1 E5 j+ N: L587 f+ M6 C, A4 c+ m( a
59
" ]3 ?2 G: H* A( v' A& Y+ i: [600 z0 x+ |$ t" Z: m$ g
61! f2 w2 [; \/ K/ M; p
622 ~# N9 S8 z6 F B
63
- F; j& Q% t( e# s( x# {7 q64; p# M" b$ D& Q0 k B
65
) m. D F+ m8 m. n66
3 J. p9 F" z5 n- m; y5 E& ?) v67
9 v' i' l; B( f, v( S* I& ^68 V+ ]8 ^7 p% g$ h$ h6 N
69
6 n7 h/ a- \* ~6 b' Q70
' h1 w+ k* \) `$ I' P71
# N2 T5 t" H- Y* e/ d8 J724 F( _8 t! V; w4 ~3 @
73
4 K7 M1 u0 U% H' Q, O* s74
+ M4 Y+ x9 |! r3 x) f75+ W" y; G# x- u6 M
76 U* M, G$ Z5 A* R c
77- | e9 }% y- I$ Q O) N" v7 n$ G8 c
78
& u h( ?, a2 K9 P79
. f% {5 u& {, N% @: P7 T80+ e* ^6 p" h* r4 a4 ^; j9 f* S
81
6 O/ \. H& J5 U I, ^82. l9 H) m2 i, l' V- p5 [8 J+ v
83
& m& B5 t' |" U/ c84
- c" I6 Y5 X Q2 u4 s859 j! J8 D" R* K0 n
86) @; X' t( `5 u: a
87
2 \6 n' ^% `3 y3 a7 _8 N88
7 @! |' x: x. N: X. U0 Z89' F& S' p0 X- B$ w: i; C
90
! F* `6 x& m( v8 [- i; p91
; N+ x4 a1 d, P0 U: s a/ }+ v92
) g' d8 R' Y$ v& E5 x# J9 a* b939 f# a4 c. Y: K H& i w4 Y- f
94
: C: m3 c3 t: N5 a. W95
4 y" Q1 l# V3 H( y963 H' b" }1 z; n. N7 o( F
97
# }0 Y7 x5 y% Y3 j; O* m98
4 C# F: W, M7 }* ]- V1 i991 t3 V p# I) \8 n
1006 F. \' [/ v; ]3 i$ {
101" ]9 g: R, l9 h9 W
1020 V. Q. x9 @2 t+ R
103' @9 m' f8 f, o0 d
104( x5 j; @2 A+ W' Y" V* @
105
3 d% z; o! d9 f( q8 X106
7 i8 h6 @; I% B! E) ^0 V2 m+ B, r107. p: h2 c6 s' ?5 V2 \4 E
108
9 U* { v* y6 S6 f7 X6 b* t V109
( T5 I! R# X& ~3 Z3 v$ v110% X1 f" f% p' d0 c- n7 u
111
, x) b1 w: O) t: x, i4 ?% ` A112
* i' I9 ~) G: Y113
2 `) N! ~+ I* L6 Y) q1 I( }114
: E9 n; e6 p0 r0 o115
2 x- |/ d5 G1 }' P5 e116
' @3 V# I2 t* d1 d117
5 t) Z J' H& F118
- y6 j1 N0 v, A" l2 ?119
+ A5 Y5 M6 S$ q* e$ y2 ~120
2 G% p% M0 n( n9 `0 I& D1217 Y3 x+ v- p$ D* u8 v2 A6 v
1227 G& E( E- b4 V+ f- [ S
123
l1 y$ N" f- D- o124
: N6 F" _! C; e) F/ K( m5 @125
6 @9 u1 i% e y. v' q- i9 ?4 y126+ a# K* Z* N1 j- E! q$ I
127
# ?/ ], _4 L/ u1286 S( d f* b0 w6 h) V
1293 j& z; C, U: t( ?: ]
1300 h* V+ R+ n3 {% g
131
3 \, D2 {* K/ w6 T6 A6 T132: c$ {; x1 z% [8 D+ U' Q
1336 ?# M0 R$ [" U8 W1 K3 P6 A
134# H! U7 B1 G# S2 q7 z0 |* U/ ~
135
6 G" S; _# C/ g/ T: `1368 T( v! @# ]9 D8 |7 ^1 [& i& P
137
2 f- G6 x* H6 A3 E z1388 M% {: h* @0 `% {* o- F" y; e; x
139
$ i( b4 c5 w6 K$ Y6 W140 d8 ~" [( Q2 c
141
# P3 `. T/ p1 v5 y9 i142+ W' F; o8 \/ C" ]& C
143 Q9 n4 l1 }1 G' @1 E) x7 }' w' a
144
% C# \6 f; ]; I( `( ~$ d% [% j& c145
) n6 ~& A. S/ ~& ~, i146
* r w! {8 T8 ?147
% O, C' z8 q( G& g6 J148
. a9 x3 e5 w, y6 j+ B$ X7 X9 T149
) t: M3 h1 y9 Y8 V1 ]! y1503 ]" X& x) y) q+ `+ ^, v9 Q! m' n
151
7 ]0 Q2 C! I: t+ Z. M# Z152
( M( S7 Q8 G: t, A1 m3 e" a153& }4 q; _4 \! \: H4 w5 |/ w
154
9 J9 x$ a0 S+ H# g$ n155
5 C7 k4 k( W" M/ f0 e! ~156
8 {0 ~- `" S$ U8 I& t157
- n1 _& [- t/ j% n158
( y+ A8 e; y& K' X1 E159. C5 v# S+ B/ R, u4 C
160, F$ u. ?+ L' B( n) m
161" @; c& }" U. v& I1 ^2 j
162) K* x8 `/ E0 \3 A" R# |3 p; x1 U- g
之所以把___Solve_oneTest()單獨寫成一個函數 而是放到main函數的for循環裡面, 因為: 當我們要進行特判 比如if( N==0){ cout<<"YES"; return;} 這裡的return 就是結束當前測試, 可是 如果你放到for循環裡面 你可能認為 那用continue不就可以了? 錯誤, 因為如果你內部還有for循環 這就出錯了 即此時continue不是對*外部的for循環*生效; 所以 必須要寫成函數形式;
9 t4 Z: v) U% }- R8 U7 N* q) N$ ^! R
Global_Initialize
$ {6 Q5 e& @8 Y7 i" s. }专为力扣设计的, 即全局(多组测试数据所共用的)数据的初始化;
# q) C# g# |3 t. C( i
, b: v7 `9 X/ ~7 l8 b+ q, ]String
) ~2 S2 a" p4 A9 `Split的答案 一定不会有空字符串;/ n& h R4 l# q# h6 g" k4 _
他是从前往后贪心进行的, 比如"xxx" 以xx分隔, 那就是[xx] x 即答案是最后的那个x; 比如"xxxx" 以xx分隔 那就是[xx] [xx] 即答案是空的;
& N {" N& B! B* O4 B; K; t; q& F
: x" k7 t3 ]7 R$ m M) L+ O- a@DELI;
% D3 M: I, `5 ]5 \
5 G# i2 Q3 Q4 e( s% x3 AReplace的本质 就是Split函数, 即比如你Split得到的是? X ? X ? (将X替换为Y) 则答案就是? Y ? Y ?;6 P0 r; ?/ q! @* r
. 比如S="xxxx", raw="xx", new="x", 那么答案是xx, 即先是[x] xx 然后[x] [x]; (并不是[x] xx 然后[x] x 然后x);6 Y1 D7 p1 A2 y% B2 }- A% N
4 Q4 d7 `) S |+ j7 R4 VDebug$ Q% p+ s3 R a2 e
if( ?){ Debug::__IsOpenedDebug = 1;} 和 Debug::__IsOpenedDebug = (?); 这两个 是不同的!5 Z0 O( A0 B5 B4 }% @) r1 I
前者: 他是在特定情况下 打开调试, 但是他不会关闭调试; 而后者: 他要么会打开调试 要么就关闭;
3 Y, x- p5 k( ~8 H% c" Y前者 通常用于 针对某个子流程而调试, 比如... [T] ... 最开始我们关闭调试, 然后到[T].入口时 打开调试, 然后到[T].出口时 关闭调试; 即整个过程 我们就调用了三次IsOpen = ?命令; 这通常在DFS时 使用的较多, 即符合某种条件时 进入某个DFS分支时 打开, 然后回溯回来时 关闭;- V5 q6 d1 [: {9 T4 V9 ^
而后者这种方式(即不停的根据条件 打开/关闭调试), 一般在非DFS的场景(比如FOR循环)里 会使用, 比如只对所有奇数进行调试;: z8 f- K) Y$ \+ ^/ M# B' T/ K3 \
即前者 他是针对一个连续的子段, 而后者是针对一个序列里 满足某条件的若干元素;
3 Z2 H7 ?0 \9 C5 Z1 |9 E
9 T3 j+ f/ B! k! N! R8 f/ u@DELI;% c5 H& E, r$ E9 y
/ Y$ e/ h. t/ S* H8 r
有個疑問: 為什麼要把他轉換成string 而不是直接cout輸出呢?7 v1 V& T2 ]0 }$ c* |4 [6 }5 B
. 可能是多了一层封装? (但毕竟你这个模块 就只复杂Debug输出啊 有必要再多封装一层吗?
5 M( E& p# Z1 T3 W9 L9 e2 n& O
' [0 g2 g8 g4 w8 J- Z/ z@DELI;- f2 q. U! L* |# Z# [3 l
. u1 x7 [* R8 J" [6 ]INFO_里, 不可以对#__VA_ARGS__直接用,逗号分隔, 因为他可能是INFO_( F(a,b), 3), 所以你还得判断括号;
& u! r4 h7 ^( n M- |, @) L; g4 V9 a, I/ \/ R3 ~% T" ?. m
@DELI;
4 Y' d( U5 a0 A9 l$ m& ~7 y* C: h" I* M1 |
T A[10];數組類型, 你可以直接輸出DE_(A);' i$ v" S! \4 y! D
DE_( (T(&)[5])A); 這是輸出A[0,1,2,3,4];% e9 @: I; I9 M0 a
8 l0 ?3 ?1 x% P" ~' j: jauto A = new T[2][3] (此時auto == T(*)[3]);
& u! v3 c7 @9 c, e. |. X. 要輸出他的所有元素, 此時直接DE_(A)是錯誤的(他是個指針地址), 正確語法是DE_( (T(&)[2][3])*A), 注意 *A的類型是T(&)[3], 但你把他強轉給T(&)[2][3]是可以的;
' A' z# b1 S+ F3 H- n* F% y! T3 w9 W: \* f) e1 }7 D* G. R
@DELI;
+ N6 T' F& a* H0 J* q' [
' e* r6 Z, o8 ]2 f$ y( E, V__Debug_list的參數 必須是const _H & _h, const _T & ... _t引用 不能是值傳遞;% s' r' [ E3 ^3 B) [) k
比如對於對象很大的情況(圖 本身都已經1e6級別的大小), 那麼 這已經不僅僅是效率問題了, 因為參數用的是棧空間 這是會爆棧的;& f d1 h9 Q. ^- j
$ U3 Y; t7 S# ]' v& b
@DELI;
, h# f+ D5 H- h; X u) L1 U% r3 W8 r) a
我们使用__Cout自己的重载函数 而不是去重载operator<<, 一个原因是 对于char/string基本类型的重载 此时和系统的就冲突了 (你需要再单独写个函数使用is_same去特判) 所以 不如就不使用系统重载符了 直接自己定义函数; 第二个原因是 其实把 两者本质都一样 我们自己写个__Cout函数 等于多了一层封装;( \4 }; u! \( j$ ]. o
) Z7 Q5 ]$ D- W9 V6 w
你必须要声明/定义分开 這是為了實現對嵌套的輸出, 比如对于vector< map<int,int> >的输出 他使用了Cout( map<int,int>) 因此 你必须要有其声明在vector實現函數的前面;; j0 l, t- R# ^3 ^5 B# x ?& [0 [
+ l0 z0 r: `) w. g如果是自定义类型 他会进入到Cout( T) 然后调用cout<< T, 即你的自定义类型 需要有重载运算符;
$ ^9 U% j C( R2 n" ~0 j& _) ]' ~
- Q0 f v! a( |/ g6 z@DELI;0 [1 l+ Z8 r; W
8 V q1 {$ ?. B5 O__Cout你不需要寫成 像ostream& operator<<( ostream&, T)那樣, 直接寫成void __Cout( T)即可, 這是因為: operator<<之所以要那樣寫 他是要實現cout<<a<<b<<...這個操作; 而__Cout 不會調用__Cout(a) << b這種操作;
o+ P2 J( G: o$ l' ~+ m
( A0 E) v6 N% ?7 GASSERT報警宏
( ?; ^! Y, R" a$ _#如何关闭某个子模块的ASSERT$
& f6 ? z! g, s0 \6 i对于算法模板A, 他里面有很多ASSERT_SYSTEM, 为了优化效率 如何把他们给关闭掉呢?2 n' ~# k% D C; A }
& W% ]# m7 ?, F0 X#undef ASSERT_SYSTEM_
4 j* B) [& O; }2 J9 h#define ASSERT_SYSTEM_( _op, ...) E4 U% R: L" e
namespace A{0 {$ W L" r, O: N3 L3 R6 A, k
}
1 B) D9 x7 X3 e; R3 @3 p8 B#undef ASSERT_SYSTEM_
. E6 d6 @+ f+ |2 e2 V#define ASSERT_SYSTEM_( _op, ...) if( !bool(_op)){ std::cout<<"Assertion_Failed(System):["<< #_op<< "], Hint:["<< ___SUPIMO::Debug_::__ToString_items( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< ")\n"; EXIT_;}
3 E2 w! S0 _4 @4 R t: X, t7 M6 ?1
# N1 d' Z/ w2 {3 {( k2
4 o% n2 r% E/ M2 x h3
7 h2 K& u i. e6 O' R3 M46 w0 a9 g" t9 L8 y/ G; a8 t2 e. C
5
9 G: ^9 f4 _/ c# V, B* A69 n: k8 ]( s; g
. 也不可以不写#undef, 但他会有警告warning: 'ASSERT_SYSTEM_' macro redefined;
9 e6 }: j y! \& n i' V e& d8 c0 e. u" h/ R# r# [7 U; v5 V' C
@DELI;3 C3 S' L+ O& s4 `/ r8 b" m
- q. h* m1 X& j" s g3 IASSERT_CUSTOM_: 用戶自己的程序裏面 使用這個宏; o4 B3 f. H2 |' e) I( h" l
ASSERT_SYSTEM_: 算法模板裏面的報警 都使用這個;
% @0 J7 @3 r$ l$ U# g/ T$ F, C( R) ], E: W( l. Z0 K8 o) `2 E
宏0 W# r W/ I/ U9 P7 o4 b) z
為什麼FOR_的宏定義是 (int)_r呢?9 w% m6 q$ A7 S: A4 v! A- J
對於uint32 a = 0, (a-1)的值 是111...111, 於是for( int i=0; i < (uint32)-1; ++i) 這會死循環的;
/ @6 f7 u3 X) \( O/ T) P4 M但是 把111....111 強轉為int, 她就是-1, 即int i = 0; i < (int)-1; ++i) 這是正確的;
+ P1 x. \! _# t; y9 x+ s
( u t. I: e0 ~2 |@DELI;) U0 J W, F9 B( d. X( `
; d8 G" [# t z. e
這3個報警宏 都有2個模式:
$ d- ~2 {9 u3 W4 E, _* }1(默認模式):[如代碼所示];
, {& x& e' a! X4 L2(優化模式):[你自己把他注釋掉, 這主要是為了(提高程序效率/便於找到程序BUG)];6 s! v1 @" B" Y* T1 w" k8 x
. 比如默認版本是#define A x, 那麼你就把他改成#define A (void)0 // x, (注意後面的注釋// x是不生效的 預編譯時會被清除掉 即到時候是(void)0; 而不是(void)0 // x;)/ \' F; s/ Q+ `* W% |
' C& S$ i/ t4 P; _9 c& F/ r% N
ASSERT_MSG的優化版本 即static_assert(false), 此时在开发阶段就會報錯 也就是你會發現所有的調用ASSERT_MSG的位置, 就可以发现有可能存在的错误;. W" g% G" B1 Q9 N$ H
/ A; T6 k% c9 }3 T2 w+ ~' t@DELI;
1 g4 i* i ]) D5 |
- d( g4 l( k7 z. j7 U6 a' N#ASSERT_MSG_( _msg)#
' g* ?% X: h) j/ u这是完全给用户提示的 程序无法测试其正確性 但你自己必须保证他是true; 比如取模除法 mod必须为质数, 就可以是ASSERT_MSG_( "mod必須是質數");( m& U' O8 I* {" l- A/ V. n& k
7 b7 ]9 c' N' ~. Z$ q' u! G m I! j5 T
@DELI;
0 y- ? `4 m/ T+ j3 l9 w+ W2 {/ S
4 g! _& Y7 T) ]( D4 f8 n#ASSERT_WEAK_(op) (void)0#) _( W+ U5 s6 x( }
即使op为假 也不会报警, 但你自己要保证他一定是true 这是为了效率;0 K2 x8 r7 C( v8 R) O7 i6 K
^9 W! ^3 T1 R6 k' ]- wModular% ]. c5 R$ n0 G5 H. p
Modular的設計思想是這樣的, 她有2個模式: 對於using MOD = Modular< T, X>, T必須是有符號int/int64/128;4 s5 W7 N! q5 E- l$ z$ D' ~" o
1: 你的Mod模數 是不變的const常量, 此時 這個X是常數, 即在編譯期 模數就固定了;
) r. J9 F* H9 m4 N2: 你的模數 是可以改變的, 此時這個X <= 0(你任意設置一個值即可), 此時到了運行期 你可以動態的通過MOD::Set_mod( m)去設置他的值 且這個m參數的值 即模數 她必須是在T的正數範圍;1 v- u* b& ]5 Z8 v, A1 v
不管哪個模式 假設你的T=int 你最終的模數 一定是在[0, 2147483647]的範圍內的 (而不是uint32的範圍), 而且你的值Value 一定是unsigned T類型, 為什麼要這樣設計? 因為 當你進行加法運算 此時 你不需要轉換為int64 她的加法結果 一定是在uint32範圍的;" {" Q' ^( n& h
4 P/ @" |) F6 g6 \# X. o* b, N@DELI;
8 e6 l U* {4 a# v
2 F2 r& X; c! b$ R& t( Y對於乘法操作, 如果是int32/int64 則直接轉換為int64/int128來進行乘法, 否則對於int128 則執行二進制乘法(她會調用取模加法 是不會溢出的 這就是為什麼你的模數 必須是有符號範圍); E7 T' ~5 @3 }; }9 H% r0 T
0 h) D8 {3 u% [
@DELI;
, r7 V; u1 s: d% y+ i1 A4 s8 P: @8 J. v3 z: C- Z/ i
template<class _T> Modular( _T _v)這個構造函數裡 你不能對他進行is_integeral的判斷, 因為對於__int128 他不滿足條件(可能未來編譯器會支持 但現在他的返回值是false);
0 r9 m7 A% D: B' M" `, |$ f; s
$ i1 _3 U8 L# {+ `7 r3 O; }@DELI;
5 P9 E! j5 x m, \/ ~. T( j/ s. s
9 ]5 `( f9 `% R' F基本使用
$ x( m: c6 g! G! T% s! d, I3 [" u
! f4 S6 v; Q0 o9 T! Kusing M1 = Modular<int, (int)1e9 + 7>;
) S- t8 z, Q& x8 ?5 I1 l' W: e, R' w, z" s所有`M1`的對象 他的`Mod`都是*int常量*;$ ^7 \* |& D5 B/ [0 S
- h# E9 b( x3 g# x
using M2 = Modular<long long, (long long)1e15 + 7>;
' d1 K" X, s$ a5 l m7 F所有`M2`的對象 他的`Mod`都是*long long常量*;
% C0 r, m9 Z% I/ a# f+ e2 F4 L- ^
' R1 l( y: [. P% S9 Eusing M3 = Modular<int, -1>;9 d2 u! V8 j9 a0 q7 ^( F' A8 X& t
M3::Mod = ?; // 由用戶錄入 (這行代碼必須在*運行時* 即放到函數域裡)
. f, x* x' N! M. Z3 Q) p8 H6 f所有`M3`的對象 他的`Mod`都是int類型 且等於`?`;
+ {/ k2 }- G) Q4 O2 k
$ ?! V* j4 I6 y5 g' o3 O: eusing M4 = Modular<long long, -2>;
% C/ q6 h2 z. |4 A: w" vM4::Mod = ?; // 由用戶錄入 (這行代碼必須在*運行時* 即放到函數域裡)
/ ^% s, Y; G* j& ?5 X0 p所有`M4`的對象 他的`Mod`都是long long類型 且等於`?`;
( ?5 [, u; ^, ^7 Y
2 u9 D( O0 |9 C( s# O1 @1 Y% musing M5 = Modular<int, -2>; // 注意此時要和`M3的<int,-1>`區分開來 即不能寫成`-1`, 否則`M3,M5`就共用同一個`Mod`了; L0 d6 R1 h9 x3 ?/ i: |
) o) W/ f. w' Y
& T# P, ]& f( Z: Z7 K p2 J/ y) u: g" C@DELI;/ d4 }: T$ S. {1 j! C
7 u: S e+ n4 s' `8 ~" IT_ Value; // 一定是[0, Mod)范围; 不要调用`obj.Value = xx`(他不是规格化的) 而是使用`obj = xx`;
9 i; c1 z9 _7 z! O/ I6 L1* v* G9 a, Y2 n; z/ e3 T' ]4 S0 a
#除法#
- y! {* e( @/ M' H调用a / b的前提是: (1: Mod是质数), (2: b != 0);1 F, V i: [7 @. U4 ?5 t, E
+ v8 R% u5 Y, u( e# z
@DELI;5 q, ~$ x" H* c0 P* ]; e/ g0 Y
; \/ v$ T+ I$ K2 t: f#BinaryMultiply#
# A g. S3 C# ?; _$ x: Q使用a*b(重载乘法)的前提是: Mod * Mod <= INT64_MAX; 如果是Mod+Mod <= INT64_MAX 就不能使用重载乘法了 可以使用当前的二进制乘法;
4 t& _" j7 F3 s! c4 D+ {) Y/ L% K7 m5 G
@DELI;* M, `' ?$ E% @0 K
% i" I0 h- H0 R& O, k! F4 y#__Cout#
5 p) [! f5 f" I1 a这个函数的目的是: 特判, 即对char/string/const char *的输出 重载, 之所以不是放到<<重载运算符函数里, 是因为 如果是<<重载 这些基本类型 就和系统cout的内置重载函数 冲突了;2 \' `% X# l2 \# o% s0 H" `
也就是, 比如对于vector的重载 是放到operator<<里的, 而对char的重载 是在__Cout里;
* X! ]! j$ k, ~/ h& M; |
7 G+ n$ T( _% ]6 o1 T函數
7 |7 C0 u; X- w% G#IsInInterval_#
9 A) {& R* W; A% U. IsInInterval_(c,l,r, true): 判斷是否滿足`c>=l && c<=r`, 即在這個區間裡;# f- p2 d) O' B6 L, Y b
. IsInInterval_(c,l,r, false): 判斷是否不滿足`c>=l && c<=r`, 即在這個區間外;
8 J4 p) v1 y0 E$ R5 ]1
4 } P) K! V+ n# V5 R1 `2, c5 q" g- L( n
3
% ~4 H7 O9 @7 y; u( ]+ xInteger
5 h3 [" g- w: B: e1 bGetPowerRoot( a, p), 比如令T = a^{1/p}, 则返回值为T的下取整;
# A3 v! ^: u& [4 x% L: f; v5 @9 w- `6 b# i* @
@DELI;
/ z5 o3 Y5 x6 t, K$ W- d: w- w* g/ B x" A/ @" L/ E, L
VectorToInteger和IntegerToVector是互逆的;
. q" L7 {: j: l! J2 f數字的高位 就對應 Vector的開頭; 這樣設計是因為: 對於一個整數321 我們通常是從高位開始閱讀 因此高位對應vector.front();
4 C- v' p: ?, n& Y( D$ E. q) y$ {, c. 比如, 整數321 (3是高位 1是低位) 她對應的Vector是[3,2,1] (3是開頭元素);
& _3 Y1 r. Z# E$ G, R( L( S. D( Y1 I6 ]. Z9 G2 \& @3 g
@DELI;
. E7 K3 r' _8 b1 N& X8 H" [3 x. t/ o" \; Q/ d; k
使用该模块里的任何函数 都是谨慎, 最好就是在调试期间调用, 你要充分考虑好他的实际效率问题;
' F9 J1 j3 A0 F' j4 ?; m比如VectorToInteger( {a,b,c}, 5)这个函数, 其实 你可以自己手动写成a*5*5 + b*5 + c, 没必要去调用这个函数, 因为此时你已经得到了{a,b,c} 他的长度是明确的 去调用这个函数 反而效率非常低;" l2 N5 Z' \! @3 e/ P0 f
% S- q; J `: k& D7 T4 q5 ~@DELI;" s. g) W" _9 I! y
k& p- ?* u. D% a% xvector<int> IntegerToVector( _T _a, int _len, const int _radix);9 l# Z: r1 ^ m4 }4 Y
比如a=10, radix=2, 他對應的2進制表示為1010, 那麼此時你必須保證len>=4 (否則會報警);
( ^* }) v c. G8 y% @% i G0 [. @IF(len==-1):[答案為[1,0,1,0]], @ELSE(len!=-1):[答案為[0...0,1,0,1,0](即前面補充前導零 答案長度為len)];/ D: B5 J( v# o
' O% L. ]* k. b! Z! B) U
@DELI;
& V, ^' { ~1 ]8 E8 ~ D+ j! T8 Q' o- r. L6 b
Sqrt( a, p)2 ]/ ]$ Y( E9 @) d% D: q
要確保a>=1, p>=2, 假設答案是浮點數b 且返回值是b的下取整;
B! N, L! I& ~1 q6 G這個函數的主要目的是 判斷a是否是p次冪 如果是則返回其p次根;
; c# a* K, ]. X; q. 由於b = pow( a*a*a, 1/3), 此時b可能是a-1/ a, 而答案是a, 所以要判斷 是否b+1 == a;( |0 E6 ]: i% Y7 h; G7 p1 p
9 f5 Y% p& w( s2 A( ] X3 n |
@TODO
7 _% f$ L9 U4 ~% { v% WModular里面, 我们用unsigned T来存储结果, 但实际上 你的取模值 一定是[0, T)范围的, 即只使用了一半, 这是因为 当涉及到+-时 此时不会溢出;
$ Q/ R: n$ T8 o5 x: e* ~" V& v. 但这有缺点, 当你Modular a = -2时, 此时构造函数是-2 % 5 他会变成int % uint -> uint%uint 即-2会变成uint 这就出错了!!! 因此要写成int%int;7 h( k4 |6 W' j: G: F
最好是, 你就用T来存储结果, 当相加时 他虽然会溢出 但其实他还是正确的! a += b; if(a<0){ a -= Modular;}就可以了;
/ B8 k S, F4 `0 c+ m+ J& c
; O& M# n* _- _/ H1 _6 V错误
7 k% a. R! I9 M+ n3 c' Yis_floating_point_v< Double> 他是等于0的! 因为Double是我们自己的自定义类型;# |" {. V2 b7 B5 D% t9 z6 y0 s! k4 B I
你可以写以下代码后, namespace std{ template<> struct __is_floating_point_helper<Double>:public true_type {};}, 此时 就可以了;, R: G5 x2 i" G2 E, L1 q
7 ^; s8 a0 J% G. _7 f! `算法模板编写规范
* y9 g" G0 `% n5 I$ ]# j! B \" j& G错误: Q( m" S9 X8 B
模板类 不要写构造函数, 因为我们可能写到全局域里 ST s(而不是ST s(??) 此时不能有参数;" d, I# Z1 n3 f1 M) |1 B
`. n+ g# [) |$ V2 {2 |@DELI;$ t3 [* o) q- ?# ~3 k
" a; i, Z* n% B& ^$ G不要写namespace ST{ using T = ?; vector<T> DP; void Work(){}}这种代码; 这样会导致ST是一次性的 即T是唯一的; 然而namespace不能加模板;* d8 d6 O. u# |/ P1 g8 ~3 F6 W
一种做法是: template<T> struct ST{ static vector<T> DP; static void Work(){} };, 但这样有2个缺点: (DP需要在类外定义 因为他是static), (由于ST是类 而实际上 他里面都是static的 不会用到他的对象 这就违背了类的初衷了);
1 g6 K0 t* S, y" E3 P/ J最优做法是: namespace ST{ template<T> vector<T> DP; template<T> void Work(){ 使用DP<T>;};. V3 g3 `& E1 Z. @8 E: y: A
1 P3 t" k$ X4 p$ x& B" r. F. s
性质
5 v# j7 u3 q9 R7 N( \" k- T模板类里放大数组constexpr int N = ?; int Arr[ N]; 等你用到时 再把?赋值, 这种方式 他确实是效率比vector<int> Arr要高, 但有个缺点是 你到时候的类对象 就不能放栈空间了 需要是static ST s 否则大数组就爆空间了;
2 W4 N" o& M% b! D0 r0 ^0 D+ a: {& s1 s# S! E4 B* S6 T6 Z- J A
@DELI;
1 X0 s! R0 p6 s+ G
/ D7 I( M: C/ y不需要寫一個TODO_STATIC_的宏, 對於靜態的@TODO, 你直接寫成注釋即可: @TODO: xxx, 然後實際使用時 再把他給注釋掉即可;
+ S& B) u7 i! D( u' G" g" @6 X+ l- _7 `% m
@DELI;
& \8 }7 E* K, n: z; o y" E" S2 H/ {& |% q2 J
#讓某個函數 必須在程序開始後執行一次 且只能執行一次#
8 {- B6 D# @# W& L' J5 w+ r
0 T5 | W7 s2 x2 Q: C$ _& i+ dvoid Init(){
! L: A" y9 p. N" \" Y, @ EXIT_COUNTER_(2);
$ L/ C5 t" ?& v2 A) N}9 I( y+ k& D/ I/ q( m, i/ V
@TODO: Init();
) Z9 V' z( y2 t) _+ c1
! C1 Z. E, U+ v* \2' z0 ^& H% ^9 n# `5 d$ l
3
6 c0 M7 Y* U; I8 d4& S8 ^4 Y9 \% o
這類函數 通常是不可以有函數參數的 (比如篩質數函數), 也就是 她的參數 是根據題目的最大數據範圍 而不是錄入的值;
3 P& j( D0 d3 z6 o) b+ r4 f, ?8 Y/ h7 u8 r& s$ Z$ J3 X6 \
不要用__attribute__((constructor)), 她是報錯的, 因為他不是在運行時執行的, 而我們的需求是在運行時執行;! E8 V. ?2 M+ R& |1 n8 h! L7 i/ |. p2 D
& K3 T* _# H! J7 \
@DELI;
2 w2 I1 v% @% t" Q, }, \( H- L9 {5 N
#類/命名空間的Debug調試#7 K7 @4 v; m% ~; _5 Z* a
u" u8 q* T1 I9 uclass ___X{; w% i# P0 g P {; _- c2 o
friend ostream& operator<<( ostream & _cout, const ___X & _a){
2 O! M3 @! v9 u _cout<<"\n";
2 C: k( i, v/ F( V5 M. I DE_( "___X-Debug-Begin");
+ m7 _: {& c Q( K
1 G, S2 t' q; v7 L8 U9 U, s cout<< ?; // 此時不可以使用`DE_(?) 或 `Debug::__CoutItems(?)`, 必須使用原生的`cout`;
+ i+ N, L" Q7 r5 L" S
/ v! O4 z( T; l9 Y: n: Z DE_( "___X-Debug-End");
: S2 S% @- q' M% }" A7 W }
# N) @9 I5 T5 n2 z7 r' w# g' }1 ~}: B/ X4 m0 P: Y3 q! p" s& m; k V
: m) f1 L9 g# E' z6 inamespace ___X{$ h4 b$ i+ Y. l* T- j4 [' N
void Debug(){* y: ]( |6 \. e; d3 \
DE_( "___X-Debug-Begin");3 C% Y2 C$ ^5 S8 }2 C0 `7 ~8 Z
# m4 f8 l' N$ O- p! s( o8 b cout<< ?; // 此時不可以使用`DE_(?) 或 `Debug::__CoutItems(?)`, 必須使用原生的`cout`;
/ G6 z1 q% ]+ x4 r3 `$ U
7 P+ ]" Z/ Q2 N# a# y% @9 ~4 a% E1 M DE_( "___X-Debug-End");4 A: P& m! m3 Y, I: H
}
8 ?) ~+ U7 X, b0 k& y4 V}
& |6 d: x% _0 T; Q" I3 b- l# g1 f0 }* S* X# M' l; U- y4 I( g
@DELI;
+ b4 {+ f' R3 t( W! D7 G5 T- x, J- r" ~* z+ }+ S4 _
#嵌入模板的全局变量#
3 m3 Y& s0 @$ M" H5 @" u( x) Y0 X6 A. ~5 H3 O
{ // ___XX! Q C9 i& A& l! Z/ k: x
const int ___Number = ?; // 这里就叫做全局变量; 要以三个`___`开头
. {9 J& M! t: K, w: E9 W: ~5 } int ___N = ?;3 v/ y/ h& V- u7 _1 K
for( int i = 1; i <= 5; ++i){
+ T$ A8 [& {4 N' \7 i) p& ]/ a int a = ?; // 像`i,a`这种*临时变量* 可以不用写`___`开头;# {6 }+ k; l: H0 G- {
}' `. F6 c2 i, M$ O1 }& m
" o. j+ `' h) g3 r) `} // ___XX/ J ]5 |6 D, o$ {, X8 g
# Q. e/ L- P% r a@DELI;
5 o4 N4 h" z, d7 H7 I- k9 S. o: M* G. ]; ^' t) s W! L
#Initialize函数, 强制的放到构造函数里#2 R. }0 k- j. r' E
最经典的例子是(建图)
, S7 W- c1 T* W1 s; s+ d, L3 J/ H" c8 ^9 Q' a
Graph( int _points_count_maximum, int _edges_count_maximum){}/ I+ A* |- {, f
void Initialize( int _points_count){}
_: D1 l5 I' X2 L# c& e1
0 o% G& X! I d6 Q- l6 D& S; _, M2
$ F4 d0 j3 [! d, c% T这样分来 会导致, 每次使用时 必须是: Graph G( 100005, 200005); G.Initialize( n), 也就是两个代码行 (两个操作, 两个步骤)7 } [6 U* W$ H6 R b' O% V
一旦忘记手动的调用Initialize函数, 虽然会报警, 那你还需要再去写代码 补上调用这个函数;
- f2 F2 w( V* @+ M {) e2 n8 F! j/ @' k
当我们将Initialize函数, 嵌入到 构造函数 里
# V) j J7 P& v3 ~. d$ q' I& ^
7 B! q1 i0 y' oGraph( int _points_count_maximum, int _edges_count_maximum, int _points_count){+ l1 g2 Q, Z# P/ d( v
...
# b) i1 r9 Y8 E2 x2 h- j7 Z //--& y' F8 f- ?8 T
Initialize( _points_count);7 ~8 c2 j& a5 ^: y- b8 y N, b
}
9 n* q# l& ^" H. x+ A, evoid Initialize( int _points_count){}
" _4 N. j; ^, Q
. R: P' k$ r! w( S注意, Initialize函数和原来是一样的, 只是做了两个事情:# ]8 S8 y8 W+ ^' l, d' t( d, z/ ^
1 将Initialize函数的参数 接到构造函数参数的后面 (比如, 原来构造函数参数是a,b,c, Initialize函数参数是x,y,z, 那么现在变成构造函数参数变成了a,b,c, x,y,z)
9 d7 E) k! l+ ^9 F5 j7 p2 在构造函数的最最结尾, 调用Initialize( x, y, z)函数;
% }: Y) b5 d/ A0 l. c
$ @$ ~6 G, x0 V@DELI;
a0 E0 W8 z: ^/ Y& ~: B; ]
0 t- ?, x. [! U#数组长度用函数传参来指定#
( T) Z& X I$ q8 d+ F) [, p# X1 f7 M! Y$ n5 G3 n& E2 G5 a
template< int _Maximum>
8 T v) }+ F% N) W: Nclass ST{
5 n- W# I' B4 d m' N r0 c ST(){% }, v, c# ?8 E3 j
array = new int[ _Maximum];
8 Q2 {6 R6 n8 l* V7 R; d) l, ^5 \" I }+ f1 C8 V2 W6 r4 a, A
private:3 Q& e7 O( y* n m
int * array;
2 R( G6 k0 Q# v; k};' I" U4 r; j8 Y$ v2 N4 a
$ `9 @0 k8 B* R, }/ B9 |. ?3 kThe above code should be replaced to:. C5 V, z7 i0 o) y: T
& Z5 G: f: i! M; q- p
class ST{- H$ \" L4 W. M; x+ y$ S# P0 h
ST( int _maximum)5 I) f2 V V1 s$ t4 E" D8 ^( J4 _& D
:' U. F. \+ c4 ^* {" C. ]6 o- e
maximum( _maximum){, O$ w5 }$ T9 |
array = new int[ maximum];* L) u; S; M6 p- y
}, ]8 E4 U+ g0 r0 U7 c7 N( N
private:# Q7 v" ?/ S- B4 ?8 F: F6 R
int * array;4 ~; x& m3 T3 N! G* k( Y
const int maximum;% o- L4 P: O* H9 E+ }5 Q
};
& h* Q6 I+ ]( v5 X) V {9 D2 d) C/ R" m3 ^# ^' Y9 g8 K! i) V
@DELI;
. [& V4 Q$ U, Z6 o3 R笔记
! B5 H9 M2 C( J有向无环图DAG4 Y4 W2 I0 Y3 I* A
最小路径点覆盖- \; h+ w! h+ w* a) F8 U
//{ @Snippet, `ZuiXiao LuJing DianFuGai (最小路径点覆盖)`8 R$ |) s/ q/ n. E/ K+ Y$ G, I. u
{4 f1 }( z0 v! l, L
int n = `the points-range in the DAG`;
: B" E! Q; c+ Q7 q/ s: E7 L //--2 l# K" z& ?- _: m/ u
BipartiteGraph B( n * 2, `the edges-count in the DAG`);
) h* |9 X) V* f; X B.Initialize( n * 2);8 Y( I3 ~) C& z
for( int i = 0; i < n * 2; ++i){
7 b6 R- I" f7 F, l if( i < n) B.Set_pointBelongingness( i, true);& }5 [% b. T/ I# \2 U: h1 T+ ]
else B.Set_pointBelongingness( i, false);
& v$ {; m5 ^7 C" Y: z+ P, o* l6 x" N }
* S. H% }$ g g8 ? for( `s -> t` : all edges in the `DAG`){
+ u. Z* V1 _5 f: B2 S# S% K. r B.Add_edge( s, t, 0);
& L/ Q, u: q5 w3 i' \ }
! `0 Z' M" a/ a# s# y* ?3 d3 T //--
9 S; V0 N8 Q' h* `! J+ H9 ]: } Bipartite_MaximalMatch M( &B);4 S0 u0 Q* m3 w1 @6 j, k6 w
M.Initialize();- z: C0 y& m- Y t
$(n - M.Get_maxMatch()) is the answer;
/ j3 k9 H+ t5 o, Z% O}2 a. m, [+ s* m5 x& x. m: ]+ A
//} @Snippet, `ZuiXiao LuJing DianFuGai (最小路径点覆盖)`
0 N! S+ K) K) ^% ]1 U$ W+ X$ T( I( Z7 O4 d5 j$ z1 H2 Z9 h
最小路径重复点覆盖, 最大路径独立集% P2 X& ~2 D; ]
//{ @Snippet, `ZuiXiao LuJing ChongFu DianFuGai (最小路径重复点覆盖)` `ZuiDa LuJing DuLiJi (最大路径独立集)`" N0 P& f, t& s
{
& M+ C/ M) i3 ?6 i int n = `the points-range in the DAG`;
" I; n. T2 R$ q( p3 z( f _ bool * edges[ @PlaceHolder] = $(edges[a][b] means a edge `a->b` in the DAG`;6 x% l7 f, L. D. k% e
//--
& Z! ?0 A1 ~' y2 @. I $(perform the `Floyd-Boolean` on @Var(edges));
& |$ z' M6 [2 A6 I0 a; Z //--
- }6 m, ?; l" J5 G3 k BipartiteGraph B( n * 2, n * n);
# ?9 [, J8 C3 {; s- E B.Initialize( n * 2);+ l" q2 k; H8 U( k: }- S5 |0 ?
for( int i = 0; i < n * 2; ++i){: D, }9 y& c: y! Y
if( i < n) B.Set_pointBelongingness( i, true);
9 D( X6 _/ ]. P' Q( G) H2 e4 L else B.Set_pointBelongingness( i, false);; H- z9 r4 S" M8 j
}; _+ |9 I, e, q8 j. _! A( t
for( int a = 0; a < n; ++a){' R! h6 w# Z# G. J
for( int b = 0; b < n; ++b){4 I% F8 W% G+ i! U7 \
if( false == edges[ a][ b]){ continue;}& v/ O6 }$ \* d7 W' N6 q6 Q
B.Add_edge( a, b + n);
; ]- T ^0 s' ^, r }9 N2 e7 x6 N$ Z9 L( L5 c' u
}" h* r5 }% a( t1 r9 j
//--
7 K2 t' e6 U* Z' s. Q# N$ p Bipartite_MaximalMatch M( &B);& }, _2 i* C/ Z0 \4 |5 z
M.Initialize();
- K, O( x: s Z2 C5 K3 y' X1 }( ^9 H $(n - M.Get_maxMatch()) is the answer;
2 p3 q% _/ m6 r' Q3 I# U}* A2 i# X, K! C# k4 p4 q+ _
//} @Snippet, `ZuiXiao LuJing ChongFu DianFuGai (最小路径重复点覆盖)` `ZuiDa LuJing DuLiJi (最大路径独立集)`
5 i% X5 N4 `$ J9 |% R4 W( m
3 O2 ]% \$ u4 k' V0 pDAG的终点
$ m" f0 k$ d5 r) t//{ @Snippet, `EndPoints of a DAG`
' T1 A) p: y( h{
! ^- r5 L |/ { int n = `the points-range of the DAG`;
: a& Z4 J0 h! N$ I int * departure = `int ?[ >= n]`; //< the departure-degree of a point;
3 G8 ]8 p, M( B4 \% N3 j. j0 u memset( departure, 0, sizeof( int) * n);0 u+ f( a/ @/ N0 M
for( `a -> b` : $(all edges in the DAG)){
! u2 @# q' x2 E" b7 F0 V ++ departure[ a];
1 m/ p: o1 J9 n }& d9 M5 ]& W/ F
for( int i = 0; i < n; ++i){% ?! d9 @8 P" F
if( departure[ i] == 0){6 q, p. R% E; r3 s* l' j
//< `i` is a End-Point in DAG: k1 Z7 h' @3 u" z& p% U. ] O
}
4 Y8 K# p' X7 {4 d1 g: L }
/ R$ H, ~) Q) ~, i, c3 `6 p4 n}( c! g2 b) s; w& e6 w! L% u# Y& e
//} @Snippet, `EndPoints of a DAG`' v6 f& n+ t$ o* e8 o' Z& Z" Y
' l v$ j4 U7 U2 BDAG的起点
: Z- L: J, r% h- R//{ @Snippet, `StartPoints of a DAG`! h- M7 G1 ^( a0 a" z
{
& |9 [2 n+ x/ e. u int n = `the points-range of the DAG`;/ X2 ?0 n! T, @* u: d e; P; c; }
int * incidence = `int ?[ >= n]`; //< the incidence-degree of a point;
0 C% s* |+ ~' m3 j, v memset( incidence, 0, sizeof( int) * n);
3 r5 d* Z& M& R for( `a -> b` : $(all edges in the DAG)){
' U8 E: l/ r+ u ++ incidence[ b];
- I3 a6 `3 v0 q, c1 g7 q }6 F6 U! Z- f1 j7 P& C
for( int i = 0; i < n; ++i){
% x E9 i; }. C3 n- L# q if( incidence[ i] == 0){
5 a2 ~. b, q8 ]& T' l! [ //< `i` is a Start-Point in DAG: E+ P1 k$ D6 D7 [; C& K# @. }
}
( ^# u0 E3 \8 A# `" C6 ~ }
& e, _3 v! }" z) c}8 I/ c4 S) p8 S3 B/ @% Z) W
//} @Snippet, `StartPoints of a DAG`
% s: ^( J5 u& }8 Q. Z L9 _/ m2 n [5 n
判断一个图是否为DAG, 求拓扑序
+ j+ [6 A6 F+ }7 h X! F4 abool Work(){
! h0 Q3 _# c! H9 c6 D+ |//< `1` Check whether a Graph is a DAG; `2` Get TopologySequence;
. p; T7 V$ O5 f" x5 b5 w- E int points_range = @Unfinished;
' C' }; `+ _4 [1 ]0 N int * topological_sequence = @Unfinished(an outside array whose length must `>=` @Var(points_range)); w3 x6 Y) T4 y! ~3 W
int * incidence = @Unfinished(an outside array whose length must `>=` @Var(points_range));0 t/ M4 |, x/ b# D5 F
memset( incidence, 0, sizeof( int) * points_range);
$ |6 g; @9 [2 { for( `a -> b` : $(all edges in the DAG){
# Z; G' D- m; f' a) D ++ incidence[ b];
9 J5 L5 J8 S7 t* j }6 i! e2 S; X" I$ K* @" @7 Q. _
int size = 0;. u; |2 v# h! P1 }+ M
for( int s = 0; s < points_range; ++s){% T }% W: A: O/ f) V
if( incidence[ s] == 0){
$ F: w. b5 x8 T7 c topological_sequence[ size] = s;
+ V9 p! m' B& ~3 n ++ size;
9 q7 l3 W5 @7 w4 v4 d9 K9 ^ }
9 e" {3 L1 q# ` }
$ X/ ?8 U. V1 s/ y9 K int head = 0;# u1 {# I8 b8 k& y$ ]
while( head < size){3 I$ u: Z) k' ~( R1 Q
int cur = topological_sequence[ head];
$ f3 H4 q) F* z0 l) K2 R0 O I7 C ++ head;
# [/ A# x% u9 l( G" [7 d3 Y/ F for( `a` : $(all adjacent-points of `cur`){
( u' ~7 I" D8 m -- incidence[ a];
4 [, {/ L3 N9 l) M if( incidence[ a] == 0){. I2 l& Q; u/ H& p. @3 E2 y0 B
topological_sequence[ size ++] = a;; H0 i. d) l( [( z' {! m* N! Z: [& u1 c
}
0 J$ }2 z! c: j+ u) I1 X, U7 @ }6 j) k: z) v" Z( J, D
}
* i, Y3 K1 ]# q2 u; E; C& p% G if( size != points_range){4 \: d0 X0 w3 S, z
return false;/ n3 i0 \6 l7 x# Q
}
7 t; ]- ?4 R% {; \7 P //>< The answer Topological-Sequence has been stored in @Var(topological_sequence); }8 S# n8 I* R+ `0 v$ {6 B2 k; G- s
return true;
" z9 [/ d8 `# H6 K1 ^8 i}
3 U- o. s/ b- s& z+ f: e# U7 B
; l; F( P/ S5 n7 o' C5 t Q7 Q图论8 ^7 f7 d3 l! O: [
最短路
( ?" \* n: P3 y" g* V8 XTARJAN. o5 ~9 Q0 E( k3 n% b. M" R" \: B6 g6 A3 B: M
无向图-PBCC点双连通分量% r& G: o2 `( H ^2 E3 O. `
+ 割点
8 p, s7 ?6 I# M' V* ], h
$ ~6 ~5 R8 @5 R# J$ D8 i+ u/ {- `. \1 q( Z//{ Tarjan_PBCC-Declaration
5 ^) Y, t8 ?! p. ?+ b5 utemplate< class _Edge_Type>
- @+ Z( f4 G& m; G1 M* ~7 w# d: }0 Mclass Tarjan_PBCC{' o$ z" b4 y; ?) z9 q9 u; f# ?
public:
_7 ]& f+ H, j2 K% [7 M- k const vector< int> * Pbcc;
( f9 v6 [1 S: M* G const bool * Is_cutPoint;' ^6 e. l( B2 C+ Q% o- U# Q) U; t
//-- variable ends. B' W5 P8 d, V/ k% d; m5 U
Tarjan_PBCC( const Graph< _Edge_Type> *);
" s; {" x z6 ~, D7 p; D void Initialize();2 c8 X( q) J+ g% c8 f% H7 Z
int Get_pbcc_count() const;! V, `+ C& D6 b; Z- u' I, ~/ V) K z
private:; \% x3 H2 {, b; X" h! A
const Graph< _Edge_Type> * graph;- r8 [) [6 m3 ^3 b! Z
int * stack_;5 i& {7 I' X' v+ G) C$ l: [5 s
int stack_top;
6 j- u, U$ r6 E0 M2 ] int * dfs_id;
5 b; w5 |- n6 N/ R int dfs_idCounter;3 `$ w2 p0 C4 G1 d
int * low_id;2 o' ^7 r o, a: O4 B$ E, b
vector< int> * pbcc;
& n. l% h7 T/ u- { int pbcc_count;
" l# S4 C' T% b. ^0 a& ]$ @ int dfs_startPoint;1 o# | B0 i% D9 I3 `! g% f. E
bool * is_cutPoint;
$ s/ X" e; l; b% {+ c9 B4 k( ? int cutPoint_count;5 @2 a3 |: K2 a* p
//-- variable ends. l3 X* l) x' k* Q p8 v
void dfs( int);
0 ?* ?( [# Q2 |4 M};
% T+ E( J" v. U* Q//} Tarjan_PBCC-Declaration0 s& o& q! N' j! s
- h& L; _1 `, F5 M2 k
//{ Tarjan_PBCC-Implementation
9 h) I4 w' t, S4 F9 p //{ Variable-Annotation9 H0 x; z+ W3 N" I( ^) h
//{ @Var(pbcc)
# K% [: u% _- t. f& H& V( } // + `pbcc[i]={a1,a2,...}` means that the PBCC with id `i` consists of these points {a1,a2,...}
6 e0 j6 V: y0 a Z7 G //} @Var(pbcc)
( T) T) m' l: `+ } //{ @Var(graph)
2 @7 i% E" h# z! Z, w2 n // + must be a undirected-graph, i.e., Edge[i] = Edge[i^1]
5 m5 _; I1 X1 [! o //} @Var(graph)
, L! w0 ~! J9 k( H! s: d8 B9 ~ //} Variable-Annotation
# u+ q: d' c8 U/ |template< class _Edge_Type> int Tarjan_PBCC< _Edge_Type>::Get_cutPoint_count() const{ return cutPoint_count;}- B4 `7 }* V. j2 {% |2 E
template< class _Edge_Type> int Tarjan_PBCC< _Edge_Type>::Get_pbcc_count() const{ return pbcc_count;}
0 ^ {/ z: X( v5 S- xtemplate< class _Edge_Type> Tarjan_PBCC< _Edge_Type>::Tarjan_PBCC( const Graph< _Edge_Type> * _graph)
5 c z4 d) C. y# @- ~3 n+ n :
" r6 F9 c. p+ I: w graph( _graph){& I/ W& ]0 x0 P
stack_ = new int[ graph->Get_pointsCountMaximum()];" a* d: w$ ?& |& y+ r: _" I
dfs_id = new int[ graph->Get_pointsCountMaximum()];
. t* g) o- i' k" G3 ^) n; E: T low_id = new int[ graph->Get_pointsCountMaximum()];" U H: K. I. s9 G* M
pbcc = new vector< int>[ graph->Get_pointsCountMaximum()];5 I: `; _1 f, L, w# N5 L
is_cutPoint = new bool[ graph->Get_pointsCountMaximum()];
& g# H( X- D5 c0 C0 g //--3 u8 p( g: K$ u" Y3 r, R: k* B6 w2 [
Pbcc = pbcc;
* s0 h3 t4 P6 C7 R4 j. A Is_cutPoint = is_cutPoint;
+ [* {$ h7 ^% M! v" B' |( t2 C h}
4 C% M8 B, x+ v: @" T2 \5 ^, \1 j. a" vtemplate< class _Edge_Type> void Tarjan_PBCC< _Edge_Type>::Initialize(){7 S* V6 M( M- I) x. O8 m0 W
stack_top = 0;
& k- O8 T0 K: b dfs_idCounter = 0;2 v' P- i9 e0 A: N
pbcc_count = 0;
Z1 b ]4 L4 x7 a5 H$ R x cutPoint_count = 0;
9 V* X$ f# Z* Z, u6 b* i for( int i = 0; i < graph->Get_pointsCount(); ++i){ pbcc[ i].clear();}
: [4 O W5 G( V D' p( T Q memset( is_cutPoint, false, sizeof( bool) * graph->Get_pointsCount());# S! [' p" r$ ?7 R, c$ j; t
memset( dfs_id, -1, sizeof( int) * graph->Get_pointsCount());2 M5 ^$ K& \' l- u: `
for( int i = 0; i < graph->Get_pointsCount(); ++i){
3 B5 s% g3 w1 A if( -1 == dfs_id[ i]){
* m% N6 s& G9 A6 V, X. K dfs_startPoint = i;9 t6 [5 ^% Q3 l: n* x
dfs( i);
" H& q) f6 E% T9 E8 F1 g, i }' L9 Q" B Z; `6 E9 L# k" M n6 C" I4 |$ @
}
, O) J5 u4 j* [, `}7 B7 o# r3 D# `7 u/ z0 ]; i, C2 A
template< class _Edge_Type> void Tarjan_PBCC< _Edge_Type>::dfs( int _cur){6 W- |! t7 C) X; ]0 p
stack_[ stack_top ++] = _cur;+ B! a0 X9 B0 q+ C; N
low_id[ _cur] = dfs_id[ _cur] = dfs_idCounter ++;
9 w/ b$ h( i1 k' J/ l //--5 v' A9 C& ^# z: M z5 |9 _
int cc_count = 0;
6 A; d% U' I( ~2 b" {1 w if( _cur != dfs_startPoint){ ++ cc_count;}& s# t. E) C/ o1 D- f5 z8 G
for( int nex, edge = graph->Head[ _cur]; ~edge; edge = graph->Next[ edge]){4 f6 Z0 r. R( A4 {" z6 A
nex = graph->Vertex[ edge];1 c9 Z: M" C- q' f
if( -1 == dfs_id[ nex]){
5 v* F" A# H- c1 G' x dfs( nex);7 B+ A" U9 G$ `6 P
//>< `low_id[nex]` always `<= dfs_id[_cur]`- k) m8 T/ x, X$ ~' O
if( low_id[ nex] == dfs_id[ _cur]){, z8 C+ H; w& X* I7 i- _' P7 p
++ cc_count;
/ R4 I: o- c$ L- ] if( cc_count >= 2){0 B( F+ k& Z O
is_cutPoint[ _cur] = true;1 S6 o/ q" f2 S; f4 y, J
++ cutPoint_count;
% W7 u) a) g7 U; `& M' P! w9 W! o while( true){$ o. q; ]* K; t G( Q
int c = stack_[ stack_top - 1];) t4 \- V7 e- V7 b& i. p) U
-- stack_top;
S P" A$ k8 G/ m4 W7 ?# \ 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.1 l$ U8 }, T& x# j9 g3 g! ?$ n3 B( L8 Q
if( c == nex){ break;}9 C6 I7 m! ?6 u9 u; v
}
4 i. i. i0 \+ s9 l pbcc[ pbcc_count].push_back( _cur);9 ~. P# @- X7 h) K7 U9 Y* \0 u4 y
//>< `pbcc[ pbcc_count].size()` >= 2
- C( [ ^; c/ Q" v& j ++ pbcc_count;
3 c9 k1 k$ S2 t6 k- l3 j, d; Q4 t }3 {4 K- |1 B0 w, l' H
}
( \! C1 A" @" Q" _. f, V low_id[ _cur] = min( low_id[ nex], low_id[ _cur]);
# l( @: Y" s; w+ b }
7 ~( a1 }* @, O else{ //< `nex` must on the `stack` due to the graph is Undirected9 ^; j4 a2 m) \7 Z- ^
low_id[ _cur] = min( dfs_id[ nex], low_id[ _cur]);
% f6 _" r' ?8 J }
+ K4 a" u2 t$ T# E- F" X0 f& A }
* f3 F$ j' w4 F, Q+ Z1 \ //--
8 y7 S" Q: K" d9 A if( _cur == dfs_startPoint){
3 C" J9 _, t/ P$ _) ^" Z6 w% X while( true){
4 r- Z p; E( p1 y h" g int c = stack_[ stack_top - 1];: Y4 V x" O7 _" [6 g8 t/ X C
-- stack_top;' S2 q) W9 s% I' m; V
pbcc[ pbcc_count].push_back( c);; y% }8 ]$ U. ?* v- p# M
if( c == _cur){ break;}; d$ f) s5 @7 q4 ~
}; C/ A2 i; z. h/ A1 T2 f% z
++ pbcc_count;
+ ] M& C/ _# y+ t8 M$ K }
- H; B# O# k1 r; _& E( t //>< `cc_count` means the number of Connected-Component when `_cur` was removed from the current Connected-Component (whatever `cur` is Cut-Point or not);6 V# G; z% k/ L3 T$ v7 e
}
: ~2 @" f% h) H, j//} Tarjan_PBCC-Implementation/ J7 ?; P( Q! S
9 P! O& r# G1 B% h4 P) m
无向图-EBCC边双连通分量
2 T) A3 |8 O. Q: K4 d+ 桥
1 ^$ R; k5 H* W/ G6 G& D8 c$ c! y; m2 Q! R
//{ Tarjan_EBCC-Declaration
( s8 Y, o$ X' r V1 n* m3 ntemplate< class _Edge_Type>1 @2 @4 o U( e4 m6 f
class Tarjan_EBCC{' C; v) y, b2 G5 ?. O4 A: ?7 v
public:
8 R# o" x8 M/ h const int * Ebcc_id; ~, P, u5 i1 c" ^; e" X- O
const int * Ebcc_size;+ Q( g$ e! M* a' t8 {
//-- variable ends9 e0 h+ I H- {$ m& Z* ^
Tarjan_EBCC( const Graph< _Edge_Type> *);" m0 |0 {8 p8 r; N
void Initialize();4 J4 ~2 I! H7 `
int Get_ebcc_count() const;( {) Y' r. M, v8 r& D) F
const Graph< _Edge_Type> * Build_tree() const;
! P5 N7 d2 Z' O- q# fprivate:4 Z6 i) m0 X! y
const Graph< _Edge_Type> * graph;. @/ [4 Q4 B, @% j/ Q b+ ^
int * stack_;/ G P( v, w* M" s, ~# C; m! m6 j
int stack_top;- q4 |+ S/ j" s2 P% K" X( Q
int * dfs_id;3 J9 F) V5 |) j) h0 L
int * low_id;
& q& ?- U7 t. b! \ int dfs_idCounter;
5 Z+ k7 o k7 R- H% _$ b int * ebcc_id;
" W& m D. n3 r" T$ A int * ebcc_size;
5 {& [# q( P6 K t1 w! w/ b$ H int ebcc_count;
. h1 K; b2 X" ~. n. @: [4 _& ^+ Y //-- variable ends& B2 [# ~7 H. b
void dfs( int, int);! _' q. `' a4 m0 M d
};
L% n% N2 y) R( ?7 e m. Y4 I- m//} Tarjan_EBCC-Declaration2 k. e) L, B7 g$ f
. f( T; J" b! B5 N" | b//{ Tarjan_EBCC-Implementation
9 E9 |$ Q7 ~; O& v4 c: T //{ Variable-Annotation
1 {1 d# |6 h4 E( J, o* N, j //{ @Var(graph)
& E/ e9 E+ R0 j% ?# D" k+ O+ [ // + must be a undirected-graph, i.e., Edge[i] = Edge[i^1]
5 l0 E/ m1 W; }" O8 Y- w% o //} @Var(graph). O# ]4 P! l, u
//{ @Var(Ebcc_id)
" r* N3 _# s$ u' \5 b8 A // + `y=Ebcc_id[x]` where `x` is a point of @Var(ptrRef_graph) and `y` belongs to `[0, @Func(Get_ebcc_count)-1]`0 g' l- q3 ^5 x4 s
//} @Var(Ebcc_id)/ }) C% Y* L* \ Z; _7 T* `
//{ @Var(Ebcc_size)
' z1 w4 T2 k) W // + `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)
C+ j9 y. @. s" y0 @1 G, Z //} @Var(Ebcc_size)1 I$ }$ W, X; v
//} Variable-Annotation
$ k3 P1 I1 a8 E8 l% @; H1 ]template< class _Edge_Type> Tarjan_EBCC< _Edge_Type>::Tarjan_EBCC( const Graph< _Edge_Type> * _graph)# f; z. G: L1 f8 V7 x0 \
:
8 x8 s5 Q" l. I% ` graph( _graph){
6 u$ o0 E7 s: s. o; o; K# K stack_ = new int[ graph->Get_pointsCountMaximum()];
. O. a- j6 N& h ebcc_id = new int[ graph->Get_pointsCountMaximum()];
& A# v. G9 Z7 v$ x( { ebcc_size = new int[ graph->Get_pointsCountMaximum()];
$ Q# i: C/ z1 M5 p8 ~# d dfs_id = new int[ graph->Get_pointsCountMaximum()];5 y) p9 r4 v* i" d. `! d
low_id = new int[ graph->Get_pointsCountMaximum()];. P2 C! H1 |5 F. b( b' N, T
//--
+ L d7 q/ F3 g7 O Ebcc_id = ebcc_id;
5 z0 c- h5 ~$ q! ~7 L7 R Ebcc_size = ebcc_size;- `& n5 i5 E$ F8 R2 U- g( d
}0 c0 s3 ^7 q6 N+ I, ?+ s7 j
template< class _Edge_Type> void Tarjan_EBCC< _Edge_Type>::Initialize(){
$ I2 N* I# s! D9 y stack_top = 0;
- h. o0 S- y, r! x$ h% `! [( h' v dfs_idCounter= 0;
3 f0 W1 o- S! c0 I ebcc_count = 0;7 [- s& m: [, E# `: y! h2 \
memset( dfs_id, -1, sizeof( int) * graph->Get_pointsCount());# u4 S. }6 W4 p" `8 f) r* i
for( int i = 0; i < graph->Get_pointsCount(); ++i){
# `0 n) `' ~( P1 e3 P* Q) ^ if( -1 == dfs_id[ i]){
8 Y; }% k4 q- R dfs( i, -1);
8 v+ S; S! G- y% f& c2 q+ a% N. e }2 i2 [$ c, g: K/ D+ y N3 x
}6 F: s! Q2 ~. O) N
}
- i: |3 O4 Q8 w5 p1 `template< class _Edge_Type> const Graph< _Edge_Type> * Tarjan_EBCC< _Edge_Type>::Build_tree() const{6 S- O3 E3 S7 \! Y! n
//< + Make sure @Func(Initialize) has been called2 C4 N, d7 X* ^$ I( c
//< + There is at most one undirected-edge between any two points in the Tree (i.e., @Ret)6 j: S2 o$ c" \4 I
Graph< _Edge_Type> * Tree = new Graph< _Edge_Type>( ebcc_count, graph->Get_edgesCountMaximum());) h: S+ H" [; v! v" x4 t7 a X4 c
Tree->Initialize( ebcc_count);! W I Z& w* |( P
for( int a, b, i = 0; i < graph->Get_pointsCount(); ++i){
( h% e s8 c+ p+ ]' ~( q; L for( int j, z = graph->Head[ i]; ~z; z = graph->Next[ z]){/ q+ j9 G9 p% t# c" o" ?
j = graph->Vertex[ z];
; X' n+ P# t, Y" E8 S" _5 Z b! O a = ebcc_id[ i];
7 ^8 H# ~7 ]& ^7 y0 X- f b = ebcc_id[ j];
0 U1 ?, d6 l! k" j: E9 y/ \ if( a != b){
6 X* j; z2 b+ V3 M // Now, there must has no edges between `ebcc_id[ i]` and `ebcc_id[ j]`
, ~ b$ g; d" m0 ` Tree->Add_edge( ebcc_id[ i], ebcc_id[ j], graph->Weight[ z]);, |9 ?7 J9 ]3 ]1 ?5 w
}
: U+ T! _7 T0 j }
1 a/ Q4 v- m; w/ P. s' V4 o% S }
1 F c1 S! p6 M! [$ [8 y return Tree;
4 A( V' L( U1 g! \& y5 Y; q}+ K l1 U* N+ ~. q4 Z/ y7 ?
template< class _Edge_Type> void Tarjan_EBCC< _Edge_Type>::dfs( int _cur, int _father_edgeId){
+ u2 N+ R& ^5 t' U stack_[ stack_top ++] = _cur;
! K" f. W) B9 {$ S+ A+ z# H low_id[ _cur] = dfs_id[ _cur] = dfs_idCounter ++;( B6 J: Z: H: x% F, y
//--
: j' g5 v6 A' ~# W8 h$ t# W for( int nex, edge = graph->Head[ _cur]; ~edge; edge = graph->Next[ edge]){
- G1 ?8 p* \( R. D, r nex = graph->Vertex[ edge];" }2 e# @( i1 p: c
if( (edge ^ 1) == _father_edgeId){ continue;}0 G% l( G ~+ J" A) l
if( -1 == dfs_id[ nex]){% i6 _% t( W5 Z" F, B3 K0 e
dfs( nex, edge);" V$ R& g$ E+ B+ D. e
low_id[ _cur] = min( low_id[ nex], low_id[ _cur]);1 I, {) u. u0 r6 i
}
" x7 H; Y% U m+ O' r3 a else{
" o+ t" W, O) {' J g/ P. s low_id[ _cur] = min( dfs_id[ nex], low_id[ _cur]);
: N3 u( j% J9 N e, C }$ F7 y% S8 e' ^7 T% B; x$ I
}
$ L( X+ L) Y; R1 x if( low_id[ _cur] == dfs_id[ _cur]){/ g% h' g/ K% [: T% r& L* {- q
ebcc_size[ ebcc_count] = 0;
/ a+ G* }: W6 R/ w B6 t0 s! b6 h while( true){
! R9 w3 G5 D) N5 r' i! E, z int c = stack_[ stack_top - 1];
9 D! z: |! A4 }* T2 z -- stack_top;" S, R3 X% u! d& k6 f
ebcc_id[ c] = ebcc_count;3 M# D/ J+ r* }' m3 s
++ ebcc_size[ ebcc_count];
G7 v/ K3 C% I; B if( c == _cur){ break;}1 ~2 Z, g. O/ t! e* _6 o
}8 I O* ?. z& q! W; H/ C" p
++ ebcc_count;* O5 b* `0 F2 w4 f
}
& C: @5 k' P( |) h% t. r/ x$ N}
; @! L9 n0 m2 z1 Q$ z//} Tarjan_EBCC-Implementation
I4 [ z3 S' I' h8 j% [% U( G v
% r2 p3 a+ ^$ _& N! @: x6 \( B* \SCC有向图强联通分量5 d3 m6 W# F: I e
//{ Tarjan_SCC) f5 V3 P% k4 g( l2 f, [: P4 v$ B
template< class _Weight_Type>
* J0 \* W5 a! I# yclass Tarjan_SCC{
0 c6 r0 w, J' t. p/ V8 e! spublic:6 @5 ]. @. F& Z& y/ n
const int * Scc_id;
: t. f% T/ X0 K" T2 c; | const int * Scc_size;
0 i; c/ b0 S6 `; g. W5 Z //-- variable ends2 H9 V& d/ w2 m0 S8 c
Tarjan_SCC( const Graph< _Weight_Type> *);6 z" z6 v$ d7 ?( g& g/ R @
void Initialize();
* j8 G( t: ?( B& `' U' F, K" U3 S; n int Get_scc_count() const;
% J- E3 s! R+ c9 E* ?: Z- `: z @, a const Graph< _Weight_Type> * Build_DAG() const;
: E7 r2 q8 b% _. q% ? const Graph< _Weight_Type> * Build_DAG_uniqueEdges() const;9 A5 H- N! r# s5 J# z
private:1 P1 V) i) P5 [) q
const Graph< _Weight_Type> * ptrRef_graph;
& f' }* I7 u2 T* T8 i& l int * ptrNew_queue;7 T2 Y- x8 o: W6 I3 ?5 U
int queue_tail;3 _$ F% y8 x( n& t8 j& S! C
bool * ptrNew_isInQueue;3 F: J' V4 o$ j% O# s% X/ s
int dfsOrderId_counter;0 }. m2 H1 r; P
int * ptrNew_sccId;
5 S+ b: }# _/ O1 F int scc_id_counter;
( U, X8 |7 p) i/ M, z$ z2 X( Y int * ptrNew_sccSize;& z2 D: _2 W% g- g3 y
//-- variable ends7 G3 c! u: M* f, {0 X" N; l* j
void dfs( int);$ d. ^5 |: f( p/ {' f2 Z; g1 v
};
% Z9 X4 b( i/ [, E& |' h//{ Variable-Annotation
0 ^" v C0 n' R, I$ y// + @Var(Scc_id)) B* H8 h& F4 X& D3 l9 a3 T
// . `y=Scc_id[x]` where `x` is a point of @Var(ptrRef_graph) and `y` belongs to `[0, @Func(Get_scc_count)-1]`) i& g( E/ ~5 w" u5 j& ]! ~, Y
// + @Var(Scc_size)
3 S+ y6 [: {& Q/ n// . `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)' t- }2 ^: }5 V
//} Variable-Annotation
E0 m/ Z" z T8 [# R! N- h& x6 [template< class _Weight_Type> Tarjan_SCC< _Weight_Type>::Tarjan_SCC( const Graph< _Weight_Type> * _graph)
0 o4 e$ [! s) n2 J6 V# i! x :/ C# | w- j% v- M- d' r- }6 k
ptrRef_graph( _graph){7 I9 X3 k% h2 C" ?3 d1 D
ptrNew_queue = new int[ ptrRef_graph->Get_pointsCountMaximum()];4 d6 [" T, M& W- [8 [
ptrNew_isInQueue = new bool[ ptrRef_graph->Get_pointsCountMaximum()];
+ x: @* G6 X8 J u* t: a ptrNew_sccId = new int[ ptrRef_graph->Get_pointsCountMaximum()];5 W% M' P# F. ^8 p) o
ptrNew_sccSize = new int[ ptrRef_graph->Get_pointsCountMaximum()];4 `( M3 f/ T; J2 e! L
//--
) O( Z7 y+ y8 }% _, Y Scc_id = ptrNew_sccId;
, ]2 B i7 K- c% p6 |, x$ o Scc_size = ptrNew_sccSize; K2 u6 Z2 b% w2 d o
}
9 {% n% O1 ~. q4 s. F5 Ptemplate< class _Weight_Type> void Tarjan_SCC< _Weight_Type>::Initialize(){
$ Y) w: e: G' L) W! Q$ g5 F queue_tail = 0;
! Z) K$ u2 W3 q: P dfsOrderId_counter = 0;1 @# V: N/ x& b5 w, [
memset( ptrNew_sccId, -1, sizeof( int) * ptrRef_graph->Get_pointsCount());/ e3 g7 l. ?' u) ~ ^$ ?
scc_id_counter = 0;
6 ]6 B) q2 w; N, q2 p for( int i = 0; i < ptrRef_graph->Get_pointsCount(); ++i){6 s* h6 Q( }! M/ ~5 B, g* {, G
if( -1 == ptrNew_sccId[ i]){
0 U5 f4 H8 v$ j3 S" [% P dfs( i);" j7 a* W9 C8 M+ B9 M# |
}
- T) `! X$ U- B: ^, |/ O }
% i! _* X7 c% Z, j6 D* F2 W1 ~" i# K}5 F1 Y* S: [' U( j
template< class _Weight_Type> const Graph< _Weight_Type> * Tarjan_SCC< _Weight_Type>::Build_DAG() const{; X) ?: O3 X. v% x/ `
//< + Make sure @Func(Initialize) has been called* R* Y" t$ I$ g0 J
Graph< _Weight_Type> * DAG = new Graph< _Weight_Type>( scc_id_counter, ptrRef_graph->Get_edgesCountMaximum());* x" z# `" f! C& [
DAG->Initialize( scc_id_counter);
! D5 ], |+ J8 E9 |0 s* |! z2 q for( int a, b, i = 0; i < ptrRef_graph->Get_pointsCount(); ++i){# {. Z6 R- b+ k4 n
for( int j, z = ptrRef_graph->Head[ i]; ~z; z = ptrRef_graph->Next[ z]){
8 Q! i8 c+ P7 w( n& x! D ` j = ptrRef_graph->Vertex[ z];$ q/ s, j* F g
a = ptrNew_sccId[ i];( v& {* r( V( d7 ^; _0 O( r+ V1 V
b = ptrNew_sccId[ j];+ Q2 a* N* q, |- V8 h" a
if( a != b){
$ q/ ~" B* s i( @' s1 n DAG->Add_edge( ptrNew_sccId[ i], ptrNew_sccId[ j], ptrRef_graph->Weight[ z]);
" f5 _0 G& K. b1 p' s+ I! V5 v }4 w6 j, x* M# f& J" l( h
}# m& d: P# h) B% H% o6 t9 `* s
}
! J2 l5 u0 y+ y* q return DAG;0 y$ j- P, r9 O$ Y" `
}
3 w; G# A4 D, l" _template< class _Weight_Type> const Graph< _Weight_Type> * Tarjan_SCC< _Weight_Type>::Build_DAG_uniqueEdges() const{
0 @# R" [$ _9 k u//< + Make sure @Func(Initialize) has been called2 a/ A* }+ V) i; }7 u: T0 O
//< + There is at most one edge between any two points in the DAG (i.e., @Ret)
5 J' O8 C, H3 d unordered_set< long long> hash_edges;9 C; v% E' g4 R" N3 B0 `
Graph< _Weight_Type> * DAG = new Graph< _Weight_Type>( scc_id_counter, ptrRef_graph->Get_edgesCountMaximum());; i6 F" F: a4 o# w2 R, P
DAG->Initialize( scc_id_counter);
! p6 f: B1 P, c& w for( int a, b, i = 0; i < ptrRef_graph->Get_pointsCount(); ++i){7 X6 Y/ r0 t1 d# m
for( int j, z = ptrRef_graph->Head[ i]; ~z; z = ptrRef_graph->Next[ z]){. ]4 h, K1 a$ Y0 x: N, P7 J: X
j = ptrRef_graph->Vertex[ z];0 {, C5 H; B. {9 Y, l5 \ h# A
a = ptrNew_sccId[ i];
& C& @( N- Z) x% ` b = ptrNew_sccId[ j];
# e5 q- f4 [8 {* S" A if( a != b){
% ~; u; Y/ ]5 Y# Q5 s long long hash_val = (long long)a * scc_id_counter + b;6 g, R* L& d# ~; @0 a4 N
if( hash_edges.find( hash_val) != hash_edges.end()){
9 p3 e+ N6 `1 N" u ~8 W( ] continue;5 B8 v0 ?6 }* G) F4 Y9 E
}
" H, ^; k% p1 N( k hash_edges.insert( hash_val);7 z8 B9 Q+ Z9 |
DAG->Add_edge( ptrNew_sccId[ i], ptrNew_sccId[ j], ptrRef_graph->Weight[ z]);& U: o( `3 z( v" Q4 R
}9 Z6 r$ Y4 z. q6 F3 y/ v6 E
}+ b& m. H% h5 t3 \
}
* r: h1 C5 s' ?- {' {7 M6 _ return DAG;$ |8 o* d+ Q- g* _, c
}+ o( w0 k$ }2 P" `: N# ~) w
template< class _Weight_Type> void Tarjan_SCC< _Weight_Type>::dfs( int _cur){2 X/ m+ X# v, U
ptrNew_queue[ queue_tail ++] = _cur;
9 z, ~* ]& O/ G0 g* a ptrNew_isInQueue[ _cur] = true;
) L5 e! g$ z: c int current_dfsOrderId = dfsOrderId_counter;
- R; B5 d& X) ?! K( w/ p ptrNew_sccId[ _cur] = dfsOrderId_counter ++;! j7 F9 ^# ]1 w' f O6 a5 A. s
//--$ H% s, p! \! D# I( @- H
for( int nex, i = ptrRef_graph->Head[ _cur]; ~i; i = ptrRef_graph->Next[ i]){
" u5 p& d9 C& F A" S) T. w nex = ptrRef_graph->Vertex[ i];
" _1 g1 @7 ~$ l* k; W4 M if( -1 == ptrNew_sccId[ nex]){$ @4 k1 b) ~/ e! Y
dfs( nex);# o8 ^) J. U4 }5 v1 B6 n: g1 M
}3 V5 m) v3 f: B( x# V1 B
if( ptrNew_isInQueue[ nex]){5 S2 r( R* b% P1 y
ptrNew_sccId[ _cur] = min( ptrNew_sccId[ nex], ptrNew_sccId[ _cur]);2 P& ]; w- Y! f9 @
}
! P: u: f" [( R+ @4 o1 B2 p }
+ T0 p& `7 c* x4 n2 D \ if( ptrNew_sccId[ _cur] == current_dfsOrderId){- \& D: I, j8 n! v, _: t
ptrNew_sccSize[ scc_id_counter] = 0;9 Z4 e7 O3 S3 r, A& ]' J; U& u# J
while( true){
8 G; K) I- G1 ~$ Z8 Q. c3 b- k r int c = ptrNew_queue[ queue_tail - 1];
8 O, ]) C6 T t; S' Q. ~" ^2 @ ptrNew_isInQueue[ c] = false;4 a Z- u1 e3 I) I
-- queue_tail;" I# n' `8 t; z, u; [( J2 p; Q; Z
ptrNew_sccId[ c] = scc_id_counter;
* I) ~. C' D" w* E9 G& [! W ++ ptrNew_sccSize[ scc_id_counter];
8 N$ ?# l6 k a- S) r" K, U if( c == _cur){ break;} C$ h+ `; N h$ E) F) k8 s
}
. M* _7 {! D8 K: O+ h O ++ scc_id_counter; q6 Z" J4 n% o, W$ L
}
; ~9 M1 ?, ^8 C9 d; C9 N/ i}/ Y+ N3 t& G4 M6 i2 u
//} Tarjan_SCC
% ^5 T) k. f9 q6 i$ S7 A" W0 T
3 Z6 `5 g: M, v+ n0 \% m差分约束系统,不等式组1 n& l0 K2 M; k0 d
//{ Minimize_InequalitiesSystem
+ f3 l" o: n4 R% Qtemplate < typename _Edge_Type, typename _Distance_Type>
/ U) D' c4 D! e" |class Minimize_InequalitiesSystem{8 s" ]) S4 G, Q. q1 N9 f
public:
$ J9 y W' N0 a$ }/ O" l& M/ Y; C const _Distance_Type * Distance;2 E. d5 R: P8 o4 w
//-- variable ends
+ R. e1 n7 G) Z+ L; S# H6 q, `8 A Minimize_InequalitiesSystem( const Graph_Weighted< _Edge_Type> * _graph)% _8 z3 T, C8 I6 ?% k9 S
:
9 @6 H7 [' L7 ?1 Z) S ptrRef_graph( _graph){% t/ u1 u& m( |6 N6 y0 O: N7 _# Y
ptr_distance = new _Distance_Type[ ptrRef_graph->Get_pointsCountMaximum()];
2 C' m x( C6 c0 w0 ^ Distance = ptr_distance;! I8 T. R7 Z- N# e5 ?
ptr_isInQueue = new bool[ ptrRef_graph->Get_pointsCountMaximum()]; g4 c( t, [, ?8 G; B" x# K
ptr_queue = new int[ ptrRef_graph->Get_pointsCountMaximum() + 1];
7 g' H4 C' W( L9 V points_range = 0;
5 r# |1 R# E" R: n' U7 M) d ptrNew_pathLength = new int[ ptrRef_graph->Get_pointsCountMaximum()];' l6 w/ w/ q& B% L
//--( q! A2 W; [! R( D" {
Initialize();
+ x* M) Z4 c+ J+ c' {2 R }7 v% O2 V9 C4 a8 R, U# Q- ?, v
void Initialize(){
. ]) g) V( e' T- E4 k points_range = ptrRef_graph->Get_pointsCount();. M$ C7 B R( ~( c4 u9 V
}
- _# c u$ @8 \* m: ?' v bool Work(){
1 M: _ ~ N) U0 t i0 y& A8 V memset( ptr_distance, 0, sizeof( _Distance_Type) * points_range);
3 z8 q8 a0 s5 J2 F {4 }* D" { memset( ptrNew_pathLength, 0, sizeof( int) * points_range);. [: B: M- F9 z
for( int i = 0; i < points_range; ++i){
- L: A: p/ F& i/ V9 |- A: T$ m ptr_queue[ i] = i;
^! [0 r1 `% v8 Y K! E }) P2 r1 C: f! I9 V. C R
memset( ptr_isInQueue, true, sizeof( bool) * points_range);! p6 {* }5 E7 g; w' U2 M1 \' L4 f
queue_head = 0;
4 v/ L9 g) { C ^5 N queue_tail = points_range;
- h+ |4 |9 `- U$ }; {" R //--1 A: k7 D, G- y" R# f" |
int cur, nex, edge;2 k2 N, ^& g6 g: [, S
while( queue_head != queue_tail){
6 l$ s; C* P5 f9 ]& s# J) l cur = ptr_queue[ queue_head ++];
4 _% D1 r+ C: ~' a' V$ s5 L( I) r ptr_isInQueue[ cur] = false;
; K- A# w, f8 d7 W/ c9 B if( queue_head > points_range){ queue_head = 0;}& @, E& o; j& g5 \ @
for( edge = ptrRef_graph->Head[ cur]; ~edge; edge = ptrRef_graph->Next[ edge]){3 B& T2 A& m2 z, S3 l( [
nex = ptrRef_graph->Vertex[ edge];7 q0 ~, M$ c3 a4 w! y! S0 M
if( ptr_distance[ cur] + ptrRef_graph->Weight[ edge] > ptr_distance[ nex]){' S: n4 ^; Q U
ptrNew_pathLength[ nex] = ptrNew_pathLength[ cur] + 1;
5 V, `3 l/ j6 A- N0 x/ I if( ptrNew_pathLength[ nex] >= points_range){, o8 n4 s/ C& b
return false;
C5 G8 B! ?3 |* o }% c% e. ]) t4 Q
ptr_distance[ nex] = ptr_distance[ cur] + ptrRef_graph->Weight[ edge];
3 Q! F% n& r* X# l* ~ q4 | if( false == ptr_isInQueue[ nex]){& t1 v. L( {6 w1 I c
ptr_isInQueue[ nex] = true;; W/ G. N- z/ O% {+ i
ptr_queue[ queue_tail ++] = nex;0 K9 e' _, J [
if( queue_tail > points_range){ queue_tail = 0;}
" r+ M$ ~7 ~; v5 U) c }
$ Z) r9 A% B! s: _ }5 g0 T5 d7 Y/ E0 R; R" D
}
! W" u) Z9 T* R# K) m5 R6 e }5 l2 a" S! j- P" R; `+ k; j& R1 E+ ]
return true;' j% [' o( g5 @$ i: i
}! N( i" R# F7 r, O, R& ]7 l2 A2 X
private:8 ^; G3 | h0 t; y. F l' [. U! h
const Graph_Weighted< _Edge_Type> * ptrRef_graph;4 v* j8 c$ j% P+ k& |
int points_range;
A4 s7 Z/ H" R! c _Distance_Type * ptr_distance;+ [3 l9 ]% l0 V; N' Z
bool * ptr_isInQueue;. c; J8 q( Q/ J: {
int * ptr_queue;* M. w* E, |& Q3 s z5 [. Y
int queue_head, queue_tail;
' N' z2 \3 U! [: G: A. K, v int * ptrNew_pathLength;
5 s! J7 H1 o# d( P9 n};& r4 v3 R5 J3 \- J3 r3 m
//} Minimize_InequalitiesSystem+ [6 S3 I9 X4 S$ {( {) K
, X, K7 E2 [- s% D
Caution! Z2 Q a4 ~% \' ^- @
& U# \7 P7 X# t+ q% t$ _' p5 |`+` You should never modify the source-code of @Func( Work), otherwise, it means your algorithm must be erroneous.
8 Z1 V5 Z4 ^) |2 ]1) `0 w# f# s/ @+ M, o" @1 W( S& g4 X
Annotation
g* H; l2 u$ C+ O$ k- u/ t Z: `/ u* F! b
`+` @Func( Work)- S9 G! K& H7 s7 d: a+ l
`1` `@Ret = true` means the Inequality-System is Consistent, otherwise it is Inconsistent (No-Solution).
1 a7 Y S1 C2 S0 J4 @% X8 _$ l`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`;! w1 N% B7 @/ T* h# J w1 w' C
`.` In other words, under the premise `all variables xi >= 0`, minimize every variable and also satisfies all relations (i.e., the graph)
$ F* j: _( {$ o! q( X
' T" n; P* ?* l`+` @Var( ptrRef_graph)
% ]* B5 D0 q, b; E, `( s7 J! f`.` A edge `x -> y` with `w` muse always means a inequality `x + w <= y` where `x,y` are both variables and `w` is a constant.* f' a) @! R- u$ W
7 x, G7 v9 H( P6 ?3 v
数论& r8 P! M* L/ g" E. O5 d
矩阵乘法
7 i( s1 }& u1 I. p* {+ z7 o( \8 k//{ MatrixMultiplication-Declaration
6 p% C+ Q! ^6 Ytemplate< class _Type, int _MaximumLength>
# H( q& Y0 g* E4 @. ]class MatrixMultiplication{0 }* ?0 u: g+ Z, X2 f# {& @
public:
b; J+ F" z. n- K+ [ MatrixMultiplication( _Type);
- |- P5 [5 X6 ^1 J3 D" M2 a: F& v void Initialize( int, _Type (*)[ _MaximumLength], const _Type (*)[ _MaximumLength], const _Type (*)[ _MaximumLength][ _MaximumLength], long long);% {: m% C% l& Z7 I. A/ q; P& |/ ~) X
private:% J) D# T- U! f5 E
_Type modulus;
" N3 D- [$ N. a; A- ~# e int length;
$ x R% |# ^. o& o: } _Type factor[ _MaximumLength][ _MaximumLength];
& L- U0 j7 c; s% |# K2 g3 i: c$ a+ ? _Type answer[ _MaximumLength][ _MaximumLength];
; A6 V z$ R9 J. i) y" v _Type temp[ _MaximumLength][ _MaximumLength];
* V8 d: f2 \, x: t2 V# E1 s) g //-- variable ends
3 s+ T/ Y- \8 A3 w3 Z8 z: I void matrix_multiplication( _Type (*)[ _MaximumLength][ _MaximumLength], const _Type (*)[ _MaximumLength][ _MaximumLength], const _Type (*)[ _MaximumLength][ _MaximumLength]);3 w$ p( y) d1 n3 V
};6 j( e3 n4 ~, c2 a* I
//} MatrixMultiplication-Declaration
- F w: t' E% M" V8 ^9 x }) b( c$ u0 K
//{ MatrixMultiplication-Implementation
# r, ]& J: a' s# x; X9 z0 H+ N! Vtemplate< class _Type, int _MaximumLength> MatrixMultiplication< _Type, _MaximumLength>::MatrixMultiplication( _Type _modulus)
( s2 g( S% P4 o :
" V" }; w$ }5 |: h3 q4 W0 L) ?6 ]1 s modulus( _modulus){" h5 Z' ]: @$ L; `$ ^9 e
}% q- w7 X+ d* z' N ~2 ~
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){
& h+ }: s. w4 Q5 e//<
P1 N2 f* i2 Z/ f% S F; f2 T) L// @Brief( a" ?& G) m% a! l# w6 b
// . `result = dp * (factor ^ k)`;6 j1 ~" \) r9 q' K8 p- _4 S+ D
// @Warning% }$ c+ W7 P+ ~
// . Make sure the data of `dp` is `dp[0, ..., _length)`, the data of `_factor` is `[ (0,0) -> (_length-1, _length-1) ]`;
+ J6 T" n. v/ o ASSERT_( _k >= 0);& T. L2 Y" X# Y$ K R7 c$ u
ASSERT_( _length <= _MaximumLength);
! _; g+ F/ y( B' v2 ]" }; E# B //----* W0 i5 ?# f7 _
length = _length;
! {8 d! a7 E4 W0 K. Q8 x //--8 k9 B7 p. U/ ^, {; v
memset( answer, 0, sizeof( answer)); W0 X% p2 R7 x! u1 W5 F1 K
for( int i = 0; i < length; ++i){
# o( \8 c1 S# q* O answer[ 0][ i] = (* _dp)[ i] % modulus; if( answer[ 0][ i] < 0){ answer[ 0][ i] += modulus;}
8 ~- ~+ D$ i. _$ \, O }! E! D) X5 s- M1 c
for( int i = 0; i < length; ++i){: f# |& c( u+ z+ @: U
for( int j = 0; j < length; ++j){- Q+ |3 Z) o* M" Q3 C& i( g Y
factor[ i][ j] = (* _factor)[ i][ j] % modulus; if( factor[ i][ j] < 0){ factor[ i][ j] += modulus;}
3 q$ X; f8 |3 l" T, F: p }6 P9 W5 l& W9 ]2 w: G: _7 @3 E9 V, E: d
}8 l6 Q i1 R' o& Q9 U
//--7 K9 Z) b* O( B6 Q
while( _k > 0){
( X2 @6 ^& U6 t4 ~ if( _k & 1){) C' C+ j6 q$ P5 a. J: Q
matrix_multiplication( &answer, &answer, &factor);2 [ \2 R K( c4 ^
}2 O5 Z& k9 z: N1 G
_k >>= 1;0 d0 k) P; t8 J1 G# B6 u
matrix_multiplication( &factor, &factor, &factor);
1 \3 q9 X; s* q6 S7 y }
% R3 l3 W9 ?% @ //--( L- b/ d4 }* b6 e/ J# O0 Z
memcpy( _result, answer[ 0], sizeof( _Type) * length); // the address of `_result` equals to the address of its first-element;
5 c; Y+ g" O! |2 L}: D. x" ]. Q( {4 _& ]
template< class _Type, int _MaximumLength> void MatrixMultiplication< _Type, _MaximumLength>::matrix_multiplication( _Type ( * _result)[ _MaximumLength][ _MaximumLength], const _Type (* _a)[ _MaximumLength][ _MaximumLength], const _Type (* _b)[ _MaximumLength][ _MaximumLength]){
: S' y+ I1 }7 i7 I0 l//<
% H$ a) t! n' z9 `4 ~2 f! G// @Brief3 p! p5 s3 [' \- U* x0 v2 k, i
// . `result = a * b`;; f& y0 I9 D, B5 @
for( int i = 0; i < length; ++i){2 R3 J# t. Y0 Z
for( int j = 0; j < length; ++j){" T2 C; b% {. @$ R$ ]! k
//>> Cuz `result` maybe equals to `a/b`, you need store the result to `temp` not `result`;$ z! C9 U4 x, ?* W; M. Q; [$ o
temp[ i][ j] = 0;
0 r0 s9 P+ Z( w' w for( int z = 0; z < length; ++z){
( j+ D1 x) }! q1 s& M temp[ i][ j] += (long long)((* _a)[ i][ z]) * (* _b)[ z][ j] % modulus; if( temp[ i][ j] >= modulus){ temp[ i][ j] -= modulus;}
" K- T* B/ E7 ]9 y* K }
% k+ X& `1 `9 e v! R: {# ` }& t' Z* P' g/ k- Q1 x
}
5 |7 f3 f$ y; q' f7 A memcpy( _result, temp, sizeof( temp));
1 X* ^+ A9 l( Z}" n+ }& p; C. E+ x; f
//} MatrixMultiplication-Implementation
/ t1 M5 L! n5 W+ O4 P) {' i3 f' K8 K: q. d
@Delimiter
6 J8 ^* L2 V( I( G" Y
% b0 J0 p3 E6 F6 B7 C. D) {/ U示例1 J7 g* M; S8 Z9 h
7 S! O2 M; ~: l! Sint Dp[ 4] = {1, 2, 2, 1};
* r0 C' e# A0 G% I2 Qint A[ 4][ 4] = {{0,1,0,0}, {1,1,1,0}, {0,0,1,1}, {0,0,0,1}};
0 N6 I5 D$ o# b% d7 j# Z+ @MatrixMultiplication< int, 4> Mat( M);' v* ?) B8 v' I9 @+ g" x* J
Mat.Initialize( 4, &Dp, &Dp, &A, N - 2);
' T$ c/ z: c; U% ]/ I$ k. n. C# W0 `
3 O: x+ @ ?4 Y; mlong long ans = (long long)Dp[ 2] * N % M - Dp[ 3];
: j0 [' [, N! Y: O+ V3 dcout<< ans;
# J7 k6 x2 w- a8 w& W1
& r% X- Y7 V" y6 Y7 B0 d: [2
9 w$ n6 J3 K$ b$ H+ E3 c3
9 P8 C/ c U1 p4 n4
/ E: w f( ^9 G5
; X4 V; [& q; `% x9 F6' C+ C+ Q6 o/ ~9 [1 R6 W
7
" z" C, {( J+ i8 Y中国剩余定理/ q: W$ {: a: m4 L0 _* u
朴素 CRT
+ D& `, c% y, p//{ CRT-Declaration0 s- W* C) ?! J9 A; d/ q1 l% @1 Q
template< class _Type> pair< long long, long long> CRT( int, const pair< _Type, _Type> *);
) Y5 n7 ] O0 B; y7 X/ M( |3 D+ _//} CRT-Declaration
) G$ v, ]4 h$ ], U9 Z6 m# z8 ^' L
2 D$ |( E: T; k: w$ a) Z' u//{ CRT-Implementation8 H. E+ [5 i* I, a: u. `4 i* A& X
template< class _Type> pair< long long, long long> CRT( int _n, const pair< _Type, _Type> * _arr){
& F9 v- K/ B" J5 @//<; l0 _6 @; f. J3 l5 ~
// @Brief
# R [, n }5 H9 \9 H// . Solve the system of `n` Congruence-Equations represented by `arr` (i.e., `? = arr[i].first (% arr[i].second)`);
. M ^8 q6 E: |- H: z// . Once all `arr[?].second` are Pairwise-Coprime, this system must be Solvable (and Infinite-Solutions);
_, |; S" V1 b6 m }- R+ Y// . @Define( `(a,m)` = @Return), `a` must in the range [0, m), and the Solutons are $a + kk * m, \forall kk \in \Z$;
5 s7 p* G# {) Z// @Warning, a& H0 E% S0 R9 A& x: {" C* H1 ?
// . Make sure all `arr[?].second` must be Pairwise-Coprime;, M8 G r) s- R6 j% L- e8 `
// . Make sure the Product of all `arr[?].second` in the range `long long`;- C r1 M+ F/ \- G
// @TimeCost
% Z' w- L$ t" X( k// . $n * 60$;
! k# j1 M3 O& m* E% ?; @* ~ long long M = 1;7 L# R: m" [" j) z0 I4 ?1 N
for( int i = 0; i < _n; ++i){, `3 T( i* C: T# ^9 Q
ASSERT_( _arr[ i].second >= 1);( n* O- |6 h, T' \( }0 O
M *= _arr[ i].second;
+ `1 b5 ~5 k5 q; Q( A, E }5 |& d- s; x) Z' d/ |; j
long long answer = 0;& ~4 e Y/ {" ? e& ?6 ?
for( int i = 0; i < _n; ++i){
6 n* y1 u4 T: P7 ^- } _Type a = _arr[ i].first % _arr[ i].second; if( a < 0){ a += _arr[ i].second;}6 C7 I& [& h' S B; g5 J9 }
long long m = M / _arr[ i].second;: _1 l) u/ q+ P* _1 R
pair< bool, pair< _Type, _Type> > ret = LCE_BezoutE< long long>( m, 1, _arr[ i].second); // m * `ret.second` = 1 (% _arr[ i].second);) G* Z$ A; t! c
ASSERT_( ret.first); // All `arr.second` are not Pairwise-Coprime which rebels the Premise-Of-This-Algorithm (See @Warning);+ G1 B/ H$ J2 v' Q( O) h, E. m' Q0 [
answer = (answer + (long long)a * m % M * ret.second.first % M) % M;
# N1 v4 a6 L8 Y0 ` }( s7 e' x O' ~1 f. u" ]# L( p6 M
return {answer, M};% N7 R( q% J* [5 _: ^% J0 b8 u
}
% _: D1 }# @; p! t% J8 I//} CRT-Implementation
/ ]4 t* a2 i I- K2 g! M! x# m. v' \! i5 b& ^. U
拓展 CRT_EX
" @# I, y* C2 l* m& w//{ CRT_EX-Declatation
( r' a/ }# T4 ]template< class _Type> pair< bool, pair< long long, long long> > CRT_EX( int, const pair< _Type, _Type> *);
7 ~6 p9 A6 v% `: [6 V//} CRT_EX-Declatation
/ j r2 w& }( B: K9 m$ o8 C
. T( i: \7 i4 I8 v+ p* ^9 t//{ CRT_EX-Implementation$ |, D( m0 y6 P9 e& e Z8 R
template< class _Type> pair< bool, pair< long long, long long> > CRT_EX( int _n, const pair< _Type, _Type> * _arr){
# A& ]( r" R \//<8 y, u0 F" [7 R g# Y
// @Brief
: ^ X3 N7 N" u9 m! F$ N9 k// . Solve the system of `n` Congruence-Equations represented by `arr` (i.e., `? = arr[i].first (% arr[i].second)`);
' A/ i4 u/ ~! W- P// . @Define( `(r1, (r2,r3))` = @Return);5 W& h7 z Q: ^$ {9 m0 i
// 0( r1=false): There is No-Solution;
+ \6 o. s3 K1 S( k5 [/ B% C, D// 1( ELSE): The Solutons are `r2 + kk * r3, $\forall kk \in \Z$`, and `r2` must in the range [0, r3);
# d0 x$ s' C9 ]# j' I: _0 z// . All `arr[?].second` maybe not Pairwise-Coprime (which differs from `CRT`);
4 v* a% }3 P; Z( }1 J+ w$ j// @Warning/ Y4 b) D" i/ J" }
// . Make sure the LCM (Least-Common-Multiple) of all `arr[?].second` in the range `long long`;
, L2 Q5 i/ Y" `; b. }- f// @TimeCost
. p9 w# p7 A x8 Y5 J// . $n * 60$;
: d ~% {& r" Q6 b. f pair< bool, pair< long long, long long> > answer;+ G0 f# L& P7 `. X* f. C
long long A, M;& \( S8 y( S# [
for( int i = 0; i < _n; ++i){
# E$ O" k3 g) N; k# b! r _Type a = _arr[ i].first;
, K% M1 g% w" R. c* ~" P a %= _arr[ i].second; if( a < 0){ a += _arr[ i].second;}
2 f k6 J# e* y% _; y1 z0 f z //--0 {4 S. t. [+ P% ^* x2 u t& J* _
if( i == 0){2 p6 {& U, @0 |2 _, @; { J( {1 L. n
A = a, M = _arr[ i].second;8 @* ?, F0 m( C9 E1 U
continue;
, g7 ?" a* x( d& K6 x+ U: m ^! z }
2 {( P* z. a K# } pair< bool, pair< _Type, _Type> > ret = LCE_BezoutE< long long>( M, a - A, _arr[ i].second);# F! Y" J5 [' O( p8 G- o" o
if( false == ret.first){( P1 @- {% ~/ K+ K; G& t+ }
answer.first = false;
$ O1 O& ^, p, D" q return answer;- [9 v8 K) f' c6 |) E. d+ A/ V; h& u
}( J; L9 p) {6 T" k0 ^$ p
_Type gcd = _arr[ i].second / ret.second.second; if( gcd < 0){ gcd = -gcd;} // The GCD of `M` and `_arr[i].second`;
: j4 o A& ~8 P _ long long new_M = M / gcd * _arr[ i].second; // LCM% Y8 A$ k# d3 O5 F
A = (A + ret.second.first * M % new_M) % new_M;
$ Y. h8 t# ~9 y% ]) t/ @6 F/ g M = new_M;
0 p" \, ^+ N: R3 J& D+ b, |9 ?; B+ ? }! H4 K) x9 h% s/ \
answer.first = true;
$ ~+ ]/ k2 }1 g3 D; ^! o answer.second.first = A;
, F" F2 e. y `2 j7 h' k0 } answer.second.second = M;- s5 T0 m2 F# p' l' q" q
return answer;1 x+ q, w( b# k5 c4 a5 x
}7 G4 q9 k" x2 f
//} CRT_EX-Implementation
& e" `1 ]9 j/ E, I- Z- M10 v5 ?# @4 x! `4 F
裴蜀方程 BezoutE8 ?. g. d4 l4 I3 P( ^
//{ BezoutE-Declaration/ e2 k2 ?* \6 M; V
template< class _Type> pair< bool, pair< pair< long long, _Type>, pair< long long, _Type> > > BezoutE( _Type _a, _Type _b, _Type _c);
/ a% E) P0 L' `//} BezoutE-Declaration
: _* }6 L! C/ b2 V# o) s9 @4 [6 v4 ~% W
//{ BezoutE-Implementation
) S7 K, O5 \" \$ j5 S9 w9 k, Utemplate< class _Type> pair< _Type, pair< long long, long long> > BezoutE_extendedGCD( _Type _a, _Type _b){
! `) g8 O' ^% M6 o J: H8 K X" }//<
! v3 B5 x$ S; P6 }+ } q/ f8 s V// @Private8 ]/ M; R1 C' O8 H& X- o
// @Warning
# H# {) r2 j$ f5 j3 y# n( L// . Make sure `a,b >= 0`, Not-Both-Be-`0`;
9 F* i' A: y2 ^( X/ M- u if( _b == 0){
6 v- c) G4 A2 C+ |. e6 a, ] return {_a, {1, 0}};& o; F% J0 b; W% o% c% H
}
4 F. m: U; ^: B x( A. ^9 L4 a2 x auto pre = BezoutE_extendedGCD( _b, _a % _b);, T) M5 ]; a( J5 i9 p
auto xp = pre.second.first;
6 {9 `# g- H. Q$ W$ \9 U% [& w auto yp = pre.second.second;
0 F Z* g/ |, H return {pre.first, {yp, xp - yp * ( _a / _b)}};) h/ k" M( L9 T" y9 t& G# X" X8 o
};
+ p2 C, Q9 o! Q6 Z/ l+ n& s& V* Wtemplate< class _Type> pair< bool, pair< pair< long long, _Type>, pair< long long, _Type> > > BezoutE( _Type _a, _Type _b, _Type _c){3 v* j9 V( F' I/ _0 h% W& F2 b
//<
$ M+ m0 c" v' Y: A1 A: K// @Brief) w7 o# y& z1 `! _
// . Solve the equation `xx * a + yy * b = c`, @Define( `(r1, ((a1,m1), (a2,m2)))` = @Return)`;
6 k, a* u7 O& B; l, Q0 r// 0( r1=false): There is no Solution;
% L& y3 q' O) L( f9 t( T// 1( ELSE): The General-Solutions are `(a1 + k * m1, a2 - k * m2) $\forall k \in \Z$`;1 R, E6 X0 i0 a0 \, h+ T9 N
// @TimeCost
; z n/ [+ |8 D- l// . $\ln(a)$;, }1 m6 s& ^6 l1 ~* C2 W
// @Warning! E# j4 L/ x( F8 q) S4 o
// . Make sure `a != 0`, `b != 0`;
& E8 p3 f# q% Q% `$ t- c$ j ASSERT_( (_a != 0) && (_b != 0));& Q% x: C/ ?/ J- L4 Z# m
pair< bool, pair< pair< long long, _Type>, pair< long long, _Type> > > answer;
# J& E' f u& \6 d; K4 f bool neg_a = false, neg_b = false;; q( [) E0 ] g. N# g, e
if( _a < 0){ neg_a = true; _a = -_a;} // `x * a + y * b = c` -> `(-x) * (-a) + y * b = c`;; u3 {0 p, V3 j0 k# n2 U& Q
if( _b < 0){ neg_b = true; _b = -_b;} // `x * a + y * b = c` -> `x * a + (-y) * (-b) = c`;
. D# u% R5 E) [7 w //--
2 Z; p5 U" f9 v( y pair< _Type, pair< long long, long long> > ret = BezoutE_extendedGCD( _a, _b);- e+ r5 p8 D; S5 Z9 v4 a0 `
if( _c % ret.first != 0){' b5 z, A) c; [% o
answer.first = false;% v0 P% C/ `3 O
return answer;* J& |0 |0 q% d0 X) Y0 j0 k/ I7 x
}7 j1 W/ j1 `% o6 e$ v
answer.first = true;+ Z8 d# Y- Q( n4 P# l/ i' A* u& {
answer.second.first.first = ret.second.first * (_c / ret.first); v1 E6 w+ O4 { I" {0 P
answer.second.first.second = _b / ret.first;* j! E h% \6 u: G, n. h* \% y
answer.second.second.first = ret.second.second * (_c / ret.first);
& W* l$ a* n9 d5 r- Z" Q answer.second.second.second = _a / ret.first;) ?0 u3 K2 }) ^
if( neg_a){ answer.second.first.first = -answer.second.first.first;}
: C, s9 i4 S4 {: [: K1 p0 X if( neg_b){ answer.second.second.first = -answer.second.second.first;}
2 o; ?8 B1 T0 ~; F6 ]6 o" B return answer;
7 a6 F6 z e: w) W- U2 u}
8 w0 s' Z3 r, s' `& |* Z. c//} BezoutE-Implementation
* g; b% s( Z" m# f" N3 R
, I( k- U" T- n# R4 J% _线性同余方程 LCE$ [: I% Q" m# w& v1 t0 T' d q+ E' z
裴蜀方程法 LCE_BezoutE/ T# E4 y# N6 w# @5 I: W+ b
//{ LCE_BezoutE-Declaration
# f7 ]! t! Q8 dtemplate< class _Type> pair< bool, pair< _Type, _Type> > LCE_BezoutE( _Type _a, _Type _b, _Type _mod);
. A6 e" o- G( U# w4 | ^//} LCE_BezoutE-Declaration8 a& k2 J* }/ N9 T
2 w7 r: k) ?4 e4 X5 \- K
//{ LCE_BezoutE-Implementation9 W. }6 D1 G! ]/ P/ d/ T
template< class _Type> pair< bool, pair< _Type, _Type> > LCE_BezoutE( _Type _a, _Type _b, _Type _mod){
* t4 e' G" J! ^- b% q//<; q$ Z* Q0 S) X- {$ f, t
// @Brief
x/ w7 ^. u" z9 C/ B// . Solve the Congruen-Equation `a * ? = b (% mod)` where `?` is @Return; @Define( `(r1, (a1,m1))` = @Return);9 v0 T$ q. u' ~! }! g" A7 `, R
// 0( r1=false): There is No-Solution;, e/ Y+ x( F2 b$ a- V5 z
// 1( ELSE): The General-Solutions are `a1 + k * m1, $\forall k \in \Z$`, and `a1` always in the range [0, m);, w( q8 l1 n' X" S' Y2 R3 R
// @TimeCost U; G5 {7 J1 s ^
// . $\ln(_a)$;" c$ e. F/ Q' S7 p
ASSERT_( _mod >= 1);
# B r' C' q- r* q" C( W pair< bool, pair< _Type, _Type> > answer;
9 i! G( l( Z# B! q9 P z _a %= _mod; if( _a < 0){ _a += _mod;}( s" o! b! `* f- W8 p$ B G
_b %= _mod; if( _b < 0){ _b += _mod;}- H/ W. e( |# Z( C& R. r" r% @8 e
if( _a == 0){- w7 a* c+ E9 m4 _" y; |
if( _b == 0){5 n! J, d E7 c6 `1 j
answer.first = true;$ f' n& l9 U) T8 \/ F1 {* U, H' `: c
answer.second.first = 0;
8 Z2 M$ G, k c$ B8 s5 Q5 x answer.second.second = 1;- L# n: O- B, y( s9 G9 _7 B
return answer;
7 |8 | y/ w# \+ V }; O! n# I" N3 p1 v
else{
) U( F! {& a& I! P answer.first = false;# E" K9 G4 ?+ J6 o8 ^/ O ^
return answer;; p) h# u9 D& e, X8 z4 S
}& a) g$ l+ D. g% ~) C3 p$ ^
}, [ ]( b* L1 P& ^- @
_Type gcd = GCD< _Type>( _a, _mod);
* P2 \8 a7 ? g( g/ L1 U9 E pair< bool, pair< pair< long long, _Type>, pair< long long, _Type> > > ret = BezoutE< _Type>( _a, _mod, gcd);
) G% J' n4 [# ?1 R+ d ASSERT_( ret.first);/ o" ^; `7 q q8 _8 O
if( _b % gcd != 0){/ A X( Y: C2 j1 k6 A' \1 H
answer.first = false;' g; [ Q' D3 S4 X
return answer;' c8 _; ~6 Z0 F1 j# X5 U
}
+ N& @2 ]- ?3 k9 p1 x answer.second.second = _mod / gcd;
# m0 H1 x- A5 Q' i; r- J answer.second.first = Binary_Multiplication< _Type>( ret.second.first.first, _b / gcd, answer.second.second);( y9 N4 P: t' z3 P
answer.first = true;+ O4 M. a5 l: z- B* x% k9 x- S
return answer;: ]2 I9 M8 f3 P7 T% M
}
p; r( B3 P2 a7 q//} LCE_BezoutE-Implementation- w3 P. p# c7 \' Y" E6 e
# {: e5 ]: j. C- l* R6 n/ W( }( p高斯消元线性方程组, x; K% P& ?, r
//{ Gaussian elimination
, U3 H3 f; t' }6 v# `% F {double Aug[ 105][ 105]; //< @Abbr( augmented matrix)! b4 d1 a/ E1 q( n% K, }# f7 \( o
int Gaussian_elimination( int _m, int _n){, N% b+ H) G* R3 C) L
//< @Par( _m): the number of equations8 S* b! @) s/ U
//< @Par( _n): the number of variables- _$ m. Z$ t. [. X( m4 b6 b' F8 B
//< @Return: (0 is unique solution), (1 is infinitely many), (-1 is no solution)6 R: H# U4 W6 p9 C
int rank = 0;/ x0 u2 A0 `1 m d- m$ E. W2 q8 t
for( int col = 0; ( col < _n) && ( rank < _m); ++col){. l) i) S+ M+ f6 h. S& v: j {
int max_row = rank;" ^5 j. x8 y1 y1 D7 h! Q5 U
for( int row = rank + 1; row < _m; ++row){# M' Y/ o: I4 G
if( fabs( Aug[ row][ col]) > fabs( Aug[ max_row][ col])){
- Y& [* v8 d5 t0 a+ Y max_row = row;
. l+ l9 M/ B! h* U# X }
2 ?" `* {- ?7 H2 E! A1 m1 |" U4 w/ } }, w. Y( h+ h$ p% M! `' J
if( 0 == Db_cmp( fabs( Aug[ max_row][ col]), 0, Epsilon)){
& C* y5 U i- U( u0 A; n( D- t //* either no solution, or infinitely many.
! ? E+ X3 k: q% D: E$ Y9 B continue;9 ~0 w0 K% Z* \" e8 g, ~7 |3 f/ `
}% |3 R3 f% z$ @. v0 B" `; R) b
//{ swap two rows
, Y* D& x& ?1 X) b" x for( int c = 0; c < _n + 1; ++c){
0 R5 ^( m8 r" D1 `: c# M v2 s swap( Aug[ max_row][ c], Aug[ rank][ c]);
0 c" l' R; ~% l/ K } r2 a) i5 D5 y( E& ]& Y
//}" }; s8 R' X+ {: w# r ]
//{ make current pivot to `1`9 h4 u: i* S2 k: D2 O' ?3 p
for( int c = _n; c > col; --c){
7 {8 V0 d: }% k9 X! l Aug[ rank][ c] /= Aug[ rank][ col];& ^' l8 F3 Y" |$ [% O
}
- G0 r- z) f# c0 t9 }0 t Aug[ rank][ col] = 1;$ M( @7 y3 P% w, R9 H4 L& R. o
//}
" l2 e* G' w! @8 ~! R1 F //{ make all rows below current pivot in the same column to `0`% n; n7 G0 l; e
for( int r = rank + 1; r < _m; ++r){8 G* } c) b2 G" T
if( 0 == Db_cmp( fabs( Aug[ r][ col]), 0, Epsilon)){
( ?$ L/ {: k% S: {( {4 \8 }1 ` U; u continue;
! y' y' m+ X* w" z$ H }
, d! _2 k( [/ o for( int c = _n; c > col; --c){
; @ J9 w% u% T% E- Y8 _ Aug[ r][ c] -= Aug[ r][ col] * Aug[ rank][ c];
! C) d. V! `. r" a5 j4 M i1 S8 e }
. m. [7 l" a5 z c+ G Aug[ r][ col] = 0;% e [$ x# \4 R$ B; I7 g# H- X+ v% P
}
8 z( [6 I! Q. `) Y ++ rank;" h: @7 e h) G) C: ]7 i9 N. j* y
}) K% k8 h: m6 W5 `/ Y* c1 s
//--
7 u* ^6 i. {0 w1 l2 U1 Q" m0 i for( int r = rank; r < _m; ++r){+ M5 N( d9 o' {
if( 0 != Db_cmp( Aug[ r][ _n], 0, Epsilon)){" E, g8 r. ^8 ^3 S( t
return -1;3 I! q# q6 \1 e8 _* I) h
}
9 n9 v0 t6 h# o& i/ m }
d3 I, O! \: J) k; l6 H if( rank != n){2 G" T9 p( \! Z/ F
return 1;
9 U0 G' B! Z0 ?6 D }
: e1 @2 R2 T/ Q# c9 P4 }( g //> the upper-left `_n * _n` submatrix of `Aug` is a identity-matrix+ Q7 \. L9 y6 w; t
for( int r = rank - 1; r > 0; --r){) J) k2 q* S! S/ e- e: V
for( int rr = 0; rr < r; ++rr){! B/ B, B8 O" t4 U T5 P+ Y- ? B
if( 0 == Db_cmp( Aug[ rr][ r], 0, Epsilon)){! i/ V% d( n( r- x* F6 r: Y
continue;
1 W/ T+ p. y( s/ G }6 m3 {" `% Q3 y' s4 b% |6 Q" B
Aug[ rr][ _n] -= Aug[ rr][ r] * Aug[ r][ _n];
/ V$ E" _4 h! A# ~ Aug[ rr][ r] = 0;$ f& H+ B* J% ?2 f
}5 }3 E) j7 A" n) j9 J" g6 E
}- R/ @: C0 ?$ I% |4 J9 Y6 e2 W
return 0;9 j) o, A* Q- d+ i0 X
}
$ ?7 w3 {5 B8 r; \. X//} Gaussian elimination& U$ p; }* o" w( k
! [) F& ?+ u; [7 V' W8 t+ D4 ?) b }6 I2 e0 [( T6 r9 Q3 L
|
|