- 积分
- 16841
在线时间 小时
最后登录1970-1-1
|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?开始注册
x
算法 {算法代码模板,算法模板编写规范}
% D4 O& r) b2 |/ X/ g, J- Q, ?supimoTemplate.cpp5 r. E8 p: a8 l" A8 X0 N5 N
代码5 ]: B& ?: N5 k0 I
#define ___SUPIMOenvir_0 J1 C5 ^! O8 g$ R6 n
7 n+ i: W5 M, f/ r5 ]* I! Q#include <bits/stdc++.h>
- X( w8 t1 _% K- t+ A% nusing namespace ::std;+ w9 F( O# [8 n. W! g; ~% C7 x
. B6 a: {7 ?7 ~) z5 ~$ \& y- r#ifdef ___SUPIMOenvir_
$ {7 r1 D. }0 {* [! O* b O #include "supimoDebug.hpp"
" n5 n$ Q/ W) G5 j# D+ m" Q#else
) }. B% S$ {9 v3 ^ #define TOstringITEMS_( ...) ""
! L1 J5 [3 Q: x: R' T5 a #define DE_( ...)
6 ]/ N$ [# o) m4 `) s. Z #define ASSERTcustom_( _op, ...) assert(_op)3 j' w# e9 ^$ W9 S2 i4 f
#define ASSERTsystem_( _op, ...) assert(_op)+ y1 d2 v5 j4 m) d& a$ L! E
#endif
' Q% z5 D- X. s: J+ `- Q$ n* n" g. k& Y( C
#define ASSERTregion_( ...) __VA_ARGS__
. s+ g% q b8 I2 X7 q- t#define ASSERTsentence_( ...)
. N6 C8 c7 h( D5 k! r8 O+ _( m#define EXIT_ std::cerr<< "\nExit(2267): Line("<< __LINE__<< ")\n"; std::exit(2267);
* K! M2 \: I* ] S9 S* C#define EXITcounter_( _max) { static int cont = 0; ++ cont; if( cont == _max){ string str = "Exit_Counter(" + std::to_string(_max) + ")"; DE_(str); EXIT_;}}
# R( d y) p6 Z6 P; N#define FOR_( _i, _l, _r) for( int _i=int(_l); _i<=int(_r); ++_i)
8 W+ I# g9 D0 h" A' y5 N#define FORrev_( _i, _l, _r) for( int _i=int(_l); _i>=int(_r); --_i)" j7 _; M+ o* |% O
W) @6 t/ D5 B7 a
using Int64_ = long long;
0 Y$ w% a' f+ i; X
2 u3 y: F: k, X7 r/ f% g. J- l) d3 h' y
/ Q: D' o M8 K& _! e* }void ___Solve_oneTest(){
9 u+ _1 D/ w2 M6 P9 W* n5 R j4 q4 t N}
( ]* r" T, i' M- c2 e# jvoid ___GlobalInitialze(){
1 v# k: V' f. H5 H7 H}
* e" T/ S4 K3 `6 Oint main(){/ m5 k7 o# Z: U- g
std::ios::sync_with_stdio(0); std::cin.tie(0);5 @; T' F2 o1 S c: q
std::cerr.setf( std::ios::fixed); std::cerr.precision( 9);
+ p, M: c( i; z# F$ Y K std::cout.setf( std::ios::fixed); std::cout.precision( 9);
( R5 e" n, O) E; P0 ?: D& C/ _& F
( `7 r6 X# L3 N# M, U+ L9 Z2 s auto ___Solve = [](){ // Problem-Input8 h9 j8 N+ D: x/ d
constexpr char MODEisSINGLE = 1;# V/ O2 M& [) ^4 t# B# a3 Q1 A+ B2 _
int testsCount;* B) S1 b$ o. n0 n
if( MODEisSINGLE){ testsCount = 1;} else{ cin>> testsCount;}; z% ~9 B! E! V; N5 N
for( int id = 0; id < testsCount; ++id){, @$ G n- N2 g0 C' H* K
if( id == 0){ ___GlobalInitialze();}
8 d! U2 m/ b, D* l* [! x' j4 X ___Solve_oneTest();/ Z( p7 A6 X8 W+ [0 b! j# O
}9 q3 i7 @9 X; V' ^+ l; A- U5 a1 _
};
3 N4 z# C& [2 n: X% b0 I#ifdef ___SUPIMOenvir_9 }' ], c( d! }
while( 1){
: R% i$ o8 t4 ]: P std::string flag; std::cin>> flag; ASSERTsystem_( flag.substr( 0, 10) == "#___Input[", flag);% M) U2 B! V( c( D/ ~
flag.replace( 4, 2, "Out");3 |! l8 @+ K9 [2 D
std::cout<< " "<< flag<< "\n"; std::cerr<< " "<< flag<< "\n";
) X5 K2 n- H- p; B5 Q! r9 f if( flag == "#___Output[-1]#"){ break;}
4 D/ W- h# C L" _6 c, ]// int timeStart = std::clock();: D) D) I$ j2 F. }2 _; s7 a
___Solve();
6 @9 n7 |! h" { ?* P8 E3 w std::cout<< "\n"; std::cerr<< "\n";3 r0 y8 g$ v2 _7 \ |- \1 w' B
// std::cout<< "TimeElapsed: "<< std::clock() - timeStart<< "\n";
1 _$ Y3 R) t T, U- J }( Z' U4 t+ q4 _2 f
#else5 Y" n4 J) Q2 l1 g }0 }
___Solve();4 ~* p* N% v6 B2 `, s
#endif& D+ h/ q5 F2 ^, c9 I, g6 q
* V5 K2 E! _# h3 T. j return 0;
2 @4 @; p. n. H}
+ t* ~6 H; t: z8 S* r' O3 n19 p0 R/ `3 d9 Y; }% Q
2% O7 l: a2 f% F @/ L$ C
3
9 G% N4 p, [, q$ R8 R. \6 E4; w7 j9 X5 Q% Z, s
5% Y: [2 N1 [2 a [
6
1 K, Q) H# k8 M. ?) a+ i! ~78 v' ~% p) f. o$ Z1 o7 L; o
8
5 n$ Y1 R0 d9 i" z. I ]; j9! u# n b( J- c" p3 H+ T
10* Z' E6 y' q6 `# g) b! y2 P
11
& O3 A) w/ u& K1 T$ G12
, M2 o* }" J% I& D. D6 d8 T138 M- v; \- b5 a& o
14
) M8 w- z* C5 D g15$ Z+ L. n& t: k" e
16
: R6 D2 v: ~8 R175 i" p' `# f$ z( T* P+ e
18
% ~) Z0 v- ~& r$ Z19
6 H. U* H2 C- z; P; g$ {, z20+ \4 y2 B. l6 x. @6 L$ ?
211 {, k0 Z; r; _5 [7 j8 U
22
7 s9 r* Y4 h) @3 U( [9 p- H& k5 ?5 M23
x8 K* `' d" t$ @/ e8 E/ _24$ `! i, t$ ?( g& d5 p+ t7 x% L
25
( `2 L* r& O+ ]7 b/ C2 [9 Q26% d% D8 {0 d0 c) s/ @ q
271 u& ]) ], f n( p |+ {# h
28
1 K5 \2 Q. X1 r& L29/ _6 e" a; X" \. U! H1 r2 C' B4 l6 A
301 u; f' h; b& a g0 ~, Y% ?6 V
31
) F {8 D! h9 S- V4 I+ R32
0 h' }# ~9 r% R j3 t8 H) F33
1 M) s% S+ b( E! A34& y9 N1 j9 C- L
35) [+ |4 P' V9 r. S8 A% `2 b
36% @; c1 H! }- v! I" V/ Y! Q
37# X- {* x" C# d6 {+ ~- m: \
38 k4 C& O& j5 f/ P ~" U
39
& \/ t# g; S5 F; `" s40! A: ]1 V. @" M2 ]+ H
41
N9 k: ~2 G# H9 h3 ^42 \' ^( i& D8 s) r& \. o$ X
43" V' ^ c; G) y5 A+ u4 T" t
44
* w# P( d2 s% i45
, ~1 L& Y' N; ^& \; v461 u& x1 L) o2 l1 c `) {
47" {+ N ?) T, _1 W9 x" L$ b/ h
48
' J1 {+ @2 x$ H, t5 y: s8 D! e49
' O! \* X7 |0 V9 r50
6 N, S! j4 ?& @8 ]; ^51
) a8 S t: A/ {. Z: ?0 J8 K# K) ^52' a% n6 y2 u: w
53
( n& l* K" @: ~) L544 Z5 H& Q- r- P0 m
55( \: w/ A6 q0 u; j6 G
563 }- [! ^, p7 @2 ?5 b8 k' \$ K
57
0 Q9 ]2 E5 `. K6 f, f( j+ [58
+ ~( i# V2 i& A3 I2 h$ Z& v59
8 F% W! w. }% g3 nsupimoDebug.hpp( ]- F/ N! k' o
代码1 r2 c2 B% S+ \1 C9 B) I$ \
#include <bits/stdc++.h>3 k6 P8 g* J2 w6 O
' [* j! I4 b6 p( x8 s
#define VARSandLOCATION_( ...) std::string(std::string("{File: ")+ __FILE__+ ", Line: "+ std::to_string(__LINE__)+ ", VarName: ["+ #__VA_ARGS__+ "]}")
8 ~$ g# S( r/ u6 c#define TOstringITEMS_( ...) ___DEBUG_::ToString_Items( __VA_ARGS__)
8 {. D3 |- k3 K, G#define DE_( ...) std::cerr<< TOstringITEMS_( __VA_ARGS__)<< " "<< VARSandLOCATION_(__VA__ARGS__)<< "\n"
" A6 w6 s, }" L( S#define ASSERTcustom_( _op, ...) if( !bool(_op)){ std::cerr<<"Assertion_Failed(Custom): ["<< #_op<< "] {Hint: ["<< TOstringITEMS_( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< "); Line: "<< __LINE__<< "}"; std::exit(2267);}/ [2 v( M0 t/ t- s% U6 W7 N
#define ASSERTsystem_( _op, ...) if( !bool(_op)){ std::cerr<<"Assertion_Failed(System): ["<< #_op<< "] {Hint: ["<< TOstringITEMS_( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< "); Line: "<< __LINE__<< "}"; std::exit(2267);}5 G( a9 w- i% L8 s5 i
" \; J# j2 B' C. ]. N' j
namespace ___DEBUG_ {2 T" B, }- f7 M2 z
//>> 所谓`Container`是指 可以通过`for( auto i : S)`来进行遍历的;$ ]* D9 [# b" q7 b9 ^: |1 z: D
template< class _t> struct __IsContainer_Unwrap : std::false_type{};
" t- p( K$ f' z* W" g' M/ r template< class _t> struct __IsContainer_Unwrap<std::vector<_t> > : std::true_type{};7 g( ~0 F/ j0 \% K) n
template< class _t> struct __IsContainer_Unwrap<std::set<_t> > : std::true_type{};
3 K& K* B% _7 M* ?2 k template< class _t> struct __IsContainer_Unwrap<std::unordered_set<_t> > : std::true_type{};% C( a& d: J- q% K/ Q2 p8 X+ d9 W1 G
template< class _t> struct __IsContainer_Unwrap<std::multiset<_t> > : std::true_type{};; _; N: P/ T) n0 X
template< class _t> struct __IsContainer_Unwrap<std::unordered_multiset<_t> > : std::true_type{};
4 p, f6 ^' {% V" `( V, p& Q, a9 N0 | template< class _t0, class _t1> struct __IsContainer_Unwrap<std::map<_t0,_t1> > : std::true_type{};5 p, u$ f) o% o$ I) Q
template< class _t0, class _t1> struct __IsContainer_Unwrap<std::unordered_map<_t0,_t1> > : std::true_type{};1 g' [0 J' |( Z. S6 h6 E* F2 |( ~
template< class _t0, int _t1> struct __IsContainer_Unwrap< _t0[_t1] > : std::true_type{};
8 l, e5 T/ y) E! \& T. J template< int _t1> struct __IsContainer_Unwrap< char[_t1] > : std::false_type{}; // 特判, 字符串常量"..."不属于容器;; s# R7 k7 b S
template< class _t> struct IsContainer : __IsContainer_Unwrap<std::remove_const_t<std::remove_reference_t<_t> > >{}; // 不能用`decay` 否则`T[N]`就退化为`T*`了;: C) I5 s# `- u4 ^
7 c6 D4 N0 r8 u0 J; i: `) u6 q template< class _t> struct __IsPair_Unwrap : std::false_type{};2 X$ y) j7 \1 d/ u8 s% I8 h
template< class _t0, class _t1> struct __IsPair_Unwrap< std::pair<_t0,_t1> > : std::true_type{};
. s3 t( X3 F8 t9 a8 \ V6 ]! w template< class _T> struct IsPair : __IsPair_Unwrap< std::decay_t<_T> >{};
! k5 K9 M& }5 \) D- ?0 F& _& |2 ^7 w( }
template< class _t> struct __IsStack_Unwrap : std::false_type{};! S1 F7 V! x+ e& y
template< class _t> struct __IsStack_Unwrap< std::stack<_t> > : std::true_type{};
, K9 |8 F8 z) c$ O. h4 } template< class _T> struct IsStack : __IsStack_Unwrap< std::decay_t<_T> >{};
% n. s4 [' @& }) s# P, `7 t! F- @+ b( t
template< class _t> struct __IsQueue_Unwrap : std::false_type{};
; n- g ~7 e3 E template< class _t> struct __IsQueue_Unwrap< std::queue<_t> > : std::true_type{};
% u9 U" o/ f1 _3 \0 B# `" S template< class _T> struct IsQueue : __IsQueue_Unwrap< std::decay_t<_T> >{};
6 C8 F8 \- k0 X4 u& r; W% b5 a
7 A! S$ h4 T$ }2 M" n1 L% B: x template< class _t> struct __IsDeque_Unwrap : std::false_type{};
+ O* [! O; }4 w" g F7 K+ k& U1 l template< class _t> struct __IsDeque_Unwrap< std::deque<_t> > : std::true_type{};7 P" V& v6 L# c' y6 {2 n
template< class _T> struct IsDeque : __IsDeque_Unwrap< std::decay_t<_T> >{};: H9 w. ~+ {* [! X, \. u4 y
3 B+ {' u/ n- x/ V5 _0 z
template< class _T> std::string ToString( _T const&);! n4 |) x% l6 w6 q* r
) q2 G6 t. E3 o H$ U/ W( Q5 Q9 ` template< class _T, int _Check> struct __ToString_Category;2 r9 v6 b6 v+ v4 O) m; \
template< class _T> struct __ToString_Category<_T, 0>{ // Single
" h0 u3 c7 }5 B2 ` template< class _t> static std::string TOstring( _t const& _v){4 m X* j7 C5 E& o4 D: p% l
std::ostringstream ANS; ANS.precision( std::cout.precision()); ANS.setf(std::cout.flags()); ANS<<_v;- |6 w6 m" B' }6 _
return ANS.str();
2 w. `" _, K( z }* H( A; p: P* V4 p8 O) Z: Q
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;}3 W( C H. {" @% s$ S9 U O8 ~; D
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 [8 }2 G5 X1 K
static std::string TOstring( bool const& _b){ return (_b?"1":"0");}
o8 V; O u7 D3 [/ ~7 Z- h! s- u static std::string TOstring( char const& _a){
* q Q/ W+ J# c. X$ w' r4 _9 ^+ F if(_a==0){ return "'\\0'";} // 否则因为她是*结束控制符* 会导致`ostream<<char(0)<<A;`后面的`A`不输出了;; q6 G& y5 f& ]4 [ ~. J, ~" v% v
std::string ANS="'?'"; ANS[1]=_a; return ANS;+ E2 E' t: U m; z" w0 T
}, K1 d) P! h0 ]$ i( a% A
static std::string TOstring( char const* const& _s){ return std::string(_s);}3 Z$ l8 I. c' g% J" G
static std::string TOstring( std::string const& _tt){ std::string ANS="\""; ANS+=_tt; ANS+='\"'; return ANS;}$ K! @; z) c/ a+ l
};
4 Z1 V. z# Q* }) v% M( X template< class _T> struct __ToString_Category<_T, 1>{ // Container; ^1 B/ O/ O! W" z, f: r9 |
template< class _t> static std::string TOstring( _t const& _v){( P; P- S4 e# n; ~$ Z2 q
std::string ANS="["; bool first=1;' |0 c1 K; _ c0 y5 [/ S) E5 f
for( auto const& i : _v){ if( 0==first) ANS+=","; if( first) first=0; ANS+=ToString(i);}% O1 ]/ k; h: ^/ w9 L2 V
ANS+="]";
/ P' A+ n/ h; Q. U) N% Y1 x6 L return ANS;5 ^' h( c4 G! i
}& w9 n3 z$ S0 R& |: t: e9 b6 g5 d
};0 Y. k! ^( j/ B2 @
template< class _T> struct __ToString_Category<_T, 2>{ // Pair& t3 ]* h9 R5 X/ P: q& z- k6 B
template< class _t> static std::string TOstring( _t const& _v){ std::string ANS="("; ANS += ToString(_v.first); ANS+=","; ANS+=ToString(_v.second); ANS+=")"; return ANS;}
1 ^9 |( E; e/ F/ X };
4 @) U4 K2 J* R0 x- w. I8 o9 m/ I template< class _T> struct __ToString_Category<_T, 3>{ // Stack
* H& L) D: W3 e+ t2 R$ ]7 A 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;}/ ?; T5 X. L' X0 R7 k
};
8 c9 s2 Z( r7 e& B. u/ c8 o template< class _T> struct __ToString_Category<_T, 4>{ // Queue, G7 ^8 D! e' ]& `
template< class _t> static std::string TOstring( _t const& _v){ std::string ANS="Queue(front)["; auto t = _v; for( bool first=1; t.empty()==0; t.pop(), first=0){ if(first==0){ ANS+=",";} ANS += ToString(t.front());} ANS+="]"; return ANS;}2 p7 K5 S, P \6 J
};
3 A- ^8 q8 a, G5 T% T9 |; T template< class _T> struct __ToString_Category<_T, 5>{ // Deque
6 m( }0 s9 e; o* Q* i% M6 x+ ^ 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;}7 h' A& o: r( y4 S
};
' L7 Y) x0 K# w/ _/ K% x
5 u R+ l z S! |* n1 @ 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)))))>{};
# C" ^$ z. q( n! S/ [- H* U; Z: _# U2 W! o7 [* A5 d; r5 J
template< class _t> std::string ToString( _t const& _v){ return __ToString<_t>::TOstring(_v);}
6 l' a: G" F {
|. F$ f5 C1 H1 J- s) s, l template< class... _H_> std::string ToString_Items( _H_ const&...){ return "";}
+ E+ B( y1 F) A/ g1 G' V! a1 s template< class _H_> std::string ToString_Items( _H_ const& _h){ return ToString(_h);}: T( k0 o. `. O6 Q) j( H
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;}! ?/ n! V# t6 J2 l
}
' f/ x+ q1 k& i: T% a( l$ N& M8 c0 h4 {" q$ `
1! o% Z8 Z) Y$ x& c/ l9 R
2
3 Y& ?( @$ R8 s8 n: z( M3* q6 F& F1 s( Y u1 k) \) j# w% A& r
4
; y& v$ Z5 c: A- L5# m$ ~. { d; ~/ ?% w( B; a
6
. H$ v4 c; j9 i' F7
( \# y, `" ]; [+ a8
# C s' j$ o M9 p' I95 K/ V+ J1 }+ y. a0 C' U S# a
10& c m& R z% y2 [
111 ?" L, H5 R/ n
12
; x% E& B4 l- |5 z" ~13
! y! P! [4 i4 n' P' m) y14
& Y3 s/ C# K* r2 L8 x! \15" y; Q9 A1 K( p1 z
16+ A! J: ]& ~$ W( D. |' ?
17
" U! y. U: }1 g6 k7 [184 A( @' G4 P4 n8 d. E5 `1 }
19
0 I) P4 E9 O3 f7 l20
. \" H5 O4 G5 }2 n' _' P0 F21 Z! n3 m7 b5 y& b
22% Q7 c& b; Z; p
23
+ X/ z( }0 U) m: x24) ~1 C. y2 J/ f- i3 {) s, \' I
25
; y( n! Y1 T: P& [9 j26$ g, L' k# y/ y n$ O
27" T" Y/ Y- D* R: `& z! \
28
4 Y# n- \: N0 [29" c' N9 Q9 D6 {5 C" F
30
' m, q) K% U6 D317 r; [' J/ T) c& s
32: F& C1 V' |, z" e5 \
33
: I; x* i9 h! ]# `1 E/ g; M345 v$ [- N/ T; t: D& y
35
1 n- N) c8 C& t+ U7 J3 x36
/ ]) o& I9 o/ }% Y37: A: i3 n: b9 d8 c0 [8 k( J, S
38
6 {2 P" S: R* Q' s39* j9 d* f# }) t; R& H' q1 J
40
; y. ^% K7 g& l% O- m. r+ A. W418 }- F# s0 |0 ]( D
42
4 O# z- E$ ?, I43- w N" f# c! z
44
! X$ g9 r/ E$ D0 l45, K e6 `2 Q9 N9 a/ f
46
* g- [! L. N: e5 Q; @475 V# f, x) w. b2 g$ k
48% \4 Z/ ^0 h2 H: [# a" ^8 O! x
498 l6 g: s2 ?3 e: Z. u" b
50 j7 y* Z; P$ ~: j9 G X
51$ p# a9 \9 B- g4 z' }; `. T" a" l
528 ` L# m7 Y- P8 N& w2 w9 q% T+ @
532 v; r3 U; |0 ?3 e4 l
54
! Y* q# N: o. C55# v; r/ d5 Y$ W, X/ B7 A6 d+ X! h
56& |$ n R# J( C, G2 W3 a: {
57
# G3 Y/ g3 B4 j; [7 d% m58
1 j" V4 Z# T4 a. k- T: F59
6 L" @7 H/ O K" Z1 p6 h60 f9 l* W( N( n& ^9 D- u
61
, e, d a. w% Q( E# @! ~3 {624 F+ Z9 W* N2 z# a
63
6 y/ ~, @* d2 H' \2 Y7 k648 f ~ W8 s" [6 T. r
65( C8 y. G1 p3 f# e9 q4 S3 y
66% ~9 r3 N# H6 W7 }; B$ y
67: T0 O6 B' j2 g. K$ F( {
68
0 `, Q+ @* q) m6 Y( Y! x. E ~) x69
9 q' i4 x6 j! k) b70; g- r! B2 O ]0 s9 z3 C# ~
71
w+ f+ _8 k# V1 u72
/ u) `4 \! M3 A$ w; N* E4 `. j73
- Q* g) p7 v2 ]. p$ X8 w* f5 p74
?4 ?* ?1 t1 Z+ d+ P3 x5 Q75
$ N, y& t/ d# L" ~8 U+ }, v" f76
4 A6 m: M0 b7 p3 A9 Q773 w6 F( c, d# v! k
78
- U; X( G! Y- _0 U& U* D, W& v! B79
; B% z$ U; L: F. w) [8 P80
/ D4 r* _ n6 w81
( ^ p: _5 s4 ~$ K82
+ x5 n3 l0 [; y2 y83) {+ l$ [+ ^( S9 F" |( D
845 P3 |# C$ {% k
851 E& K7 r7 d* i5 d' i! T: Z
86
/ H. i7 E* z' L2 L性质
0 ?" ?0 T9 P- ^$ x#TOstringITEMS_#- B5 O& u4 j! A* M r; @( {- H
这个宏 是为了: 对类进行输出时 可以直接_cout<< TOstringITEMS_(成员变量...);1 {* H9 e# U. w
你可能认为, 直接_cout<< ___Debug_::ToStringItems(...)不就行了?
' w3 N/ f+ C! |' v- Z! ^* E. o( W. 错误, 因为在最终文件里 是看不见___Debug_的, 所以写成一个宏 在最终文件里 #define TOstringITEMS_ "";
# ]5 ^/ w0 q8 L) {. {/ x
4 m& Y1 u1 j Q' G& u1 j4 a- C笔记# [& a$ j4 R* @- S3 `- R* M$ H
#以前的debug.hpp#
0 N; ]& @) Y0 S. W% `8 K9 i
2 i( ^: P- B% s2 N3 a1 W//{ omipusDebug.hpp4 v t3 U' G& I! f
#include <bits/stdc++.h>( q. S, s2 Z, V$ ` z# g
$ j# s: O/ V4 z/ X6 U#define TOstringITEMS_( ...) ___DEBUG_::ToString_Items( __VA_ARGS__)2 s7 m; b$ d! c9 b
#define DE_( ...) std::cerr<< TOstringITEMS_( __VA_ARGS__)<< " "<< "{"<< "Line: "<< std::to_string(__LINE__)<< ", Var: ["<< (#__VA_ARGS__)<< "]"<< "}"<< "\n"
, P6 f6 K/ U4 ?: _# J#define ASSERT_( _op, ...) if( !bool(_op)){ std::cerr<<"Assertion: ["<< #_op<< "] {Info: ["<< TOstringITEMS_( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< "); Line: "<< __LINE__<< "}"; std::exit(2267);}
3 w6 a, P5 P% k1 s( e#define ASSERTsystem_( _op, ...) if( !bool(_op)){ std::cerr<<"Assertion(System): ["<< #_op<< "] {Info: ["<< TOstringITEMS_( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< "); Line: "<< __LINE__<< "}"; std::exit(2267);}) B4 O M. N" x' f+ N
; \/ _" h! B9 G, h$ `- S$ L7 Y$ C( \
namespace ___DEBUG_ {# Z' \/ ]& ?, ]
template< class _t> struct __IsContainer_Unwrap : std::false_type{}; // 所谓`Container`是指 可以通过`for( auto i : S)`来进行遍历的;
& t {: z' y: z6 m+ X4 F. t- q template< class _t> struct __IsContainer_Unwrap<std::vector<_t> > : std::true_type{};
; \6 W, j1 F: c- K! S9 p template< class _t> struct __IsContainer_Unwrap<std::set<_t> > : std::true_type{};/ A7 B j. y2 C1 ]' P
template< class _t> struct __IsContainer_Unwrap<std::unordered_set<_t> > : std::true_type{};
[* c+ E1 Q$ |5 e B, I template< class _t> struct __IsContainer_Unwrap<std::multiset<_t> > : std::true_type{};6 u, p% h; \3 w
template< class _t> struct __IsContainer_Unwrap<std::unordered_multiset<_t> > : std::true_type{};
. F0 R$ `2 d1 q) I. A k template< class _t0, class _t1> struct __IsContainer_Unwrap<std::map<_t0,_t1> > : std::true_type{};. M/ L1 E: i6 l$ P" l9 ?1 i# k! T5 M
template< class _t0, class _t1> struct __IsContainer_Unwrap<std::unordered_map<_t0,_t1> > : std::true_type{};7 k, R4 {6 R+ V
template< class _t0, std::size_t _t1> struct __IsContainer_Unwrap< _t0[_t1] > : std::true_type{};, L, Q. H4 R2 W; D$ u# W
template< std::size_t _t1> struct __IsContainer_Unwrap< char[_t1] > : std::false_type{}; // 特判, 字符串常量"..."不属于容器;
- D1 a; Q8 K% C7 f: G template< class _t, std::size_t _siz> struct __IsContainer_Unwrap<std::array<_t,_siz> > : std::true_type{};
% K( Q6 `# D# x( R- A6 U template< class _t> struct IsContainer : __IsContainer_Unwrap<std::remove_const_t<std::remove_reference_t<_t> > >{}; // 不能用`decay` 否则`T[N]`就退化为`T*`了;5 ]. [/ t" i3 Q( O' X; l% J) z' O
( E( | W _) Y! v+ t4 A/ e5 S+ j
template< class _t> struct __IsPair_Unwrap : std::false_type{};4 v1 A9 l8 u5 g$ Z( e' D
template< class _t0, class _t1> struct __IsPair_Unwrap< std::pair<_t0,_t1> > : std::true_type{};) v. f3 t! w2 Y" k7 f
template< class _T> struct IsPair : __IsPair_Unwrap< std::decay_t<_T> >{};
9 Y9 [8 m) W8 s w$ \: R* Y5 O# w$ K+ ~& @8 u9 H$ c2 q8 k j0 K
template< class _t> struct __IsStack_Unwrap : std::false_type{};
# I( U% d- A) N7 P# q. c template< class _t> struct __IsStack_Unwrap< std::stack<_t> > : std::true_type{};
+ s8 c3 ?. F# f5 ~ |$ z' d template< class _T> struct IsStack : __IsStack_Unwrap< std::decay_t<_T> >{};
7 K' g. E9 i1 Z: F! A# J; q6 h7 I0 J0 W- E' e5 z
template< class _t> struct __IsQueue_Unwrap : std::false_type{};7 U& t$ {3 t3 J8 t8 J* `7 O
template< class _t> struct __IsQueue_Unwrap< std::queue<_t> > : std::true_type{};2 M0 D, m( E1 ~
template< class _T> struct IsQueue : __IsQueue_Unwrap< std::decay_t<_T> >{};$ ^; r: [' C; @5 ~8 R
7 w8 C4 E4 u# r template< class _t> struct __IsDeque_Unwrap : std::false_type{};
4 N1 r/ @& K9 o) Z) g4 c2 |) v, c template< class _t> struct __IsDeque_Unwrap< std::deque<_t> > : std::true_type{};2 Z0 {) l# ], B* I) v- L% G8 ?
template< class _T> struct IsDeque : __IsDeque_Unwrap< std::decay_t<_T> >{};, m" m, j7 t0 i/ n( l
, _$ W% l1 t* [1 W( g2 ~
template< class _T> std::string ToString( _T const&);
: F [4 F/ A: a$ v. i2 Q
& X+ J: p4 b& I/ h7 u4 M template< class _T, int _Check> struct __ToString_Category;
. T0 J! z3 \4 v! z# i template< class _T> struct __ToString_Category<_T, 0>{ // Single' T% K3 q Y0 m) l8 L4 w
template< class _t> static std::string TOstring( _t const& _v){! G) z7 l. R; ` U8 M9 T
std::ostringstream ANS; ANS.precision( std::cout.precision()); ANS.setf(std::cout.flags()); ANS<<_v;
" ~; t! {0 x* O, [! \- j8 a return ANS.str();
& o1 u7 P+ p ^4 g& A }' E* x# Y$ X9 U7 T" K! |- g8 X0 t# _
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;}" \! \, i0 E/ r' e. n
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;}/ M( i- {# \6 A$ x
static std::string TOstring( bool const& _b){ return (_b?"1":"0");}
Z- l5 B7 V% r8 U8 h9 N) { static std::string TOstring( char const& _a){
% D( ~3 _$ L: J1 ^6 Q std::string ANS="'?'";
. s: ~* e7 }& N. w! q ANS.replace( 1, 1, std::to_string(_a));
6 Q! N4 Z! `/ {0 k/ | return ANS;2 e" q0 i- W& z6 z" w( W/ C; A
}
# O- {/ [; y6 [; G8 U; T P static std::string TOstring( char const* const& _s){ return TOstring(std::string(_s));}' w% d. e3 q" w2 L. ?
static std::string TOstring( std::string const& _s){ std::string ANS="\""; ANS+=_s; ANS+='\"'; return ANS;}
/ s! I7 u) f% K };
/ B0 A" @+ J3 q) K0 e! u template< class _T> struct __ToString_Category<_T, 1>{ // Container
# y( O( n8 F! Q9 [, F& M+ T template< class _t> static std::string TOstring( _t const& _v){
2 |; z* }/ Y: Y/ G* @& O std::string ANS="["; bool first=1; for( auto const& i : _v){ if( 0==first) ANS+=","; if( first) first=0; ANS+=ToString(i);} ANS+="]";
7 b) ^7 d6 |; z% h" D n0 G: H return ANS;
' j6 K4 W3 u. Z1 C8 P& V6 m7 F }- h' x, N4 e1 \7 n. O5 S
};
) M% J6 n) {$ [ _ template< class _T> struct __ToString_Category<_T, 2>{ // Pair9 P- A, j% E" v6 M8 b
template< class _t> static std::string TOstring( _t const& _v){ std::string ANS="("; ANS += ToString(_v.first); ANS+=","; ANS+=ToString(_v.second); ANS+=")"; return ANS;}
8 `. m& z3 p& J( e/ l7 Z };; u* S/ m& { ~& G3 Z! D# J+ o: f
template< class _T> struct __ToString_Category<_T, 3>{ // Stack6 d# Y! R6 T5 A% G
template< class _t> static std::string TOstring( _t const& _v){ std::string ANS="Stack(top)["; auto t = _v; for( bool first=1; t.empty()==0; t.pop(), first=0){ if(first==0){ ANS+=",";} ANS += ToString(t.top());} ANS+="]"; return ANS;}
7 M$ q' k: i$ Z2 ?& H8 p, ~ };. Y& R \) K8 [/ G2 n4 w- U
template< class _T> struct __ToString_Category<_T, 4>{ // Queue, M* g( B% o5 Y6 ]$ g. F, t
template< class _t> static std::string TOstring( _t const& _v){ std::string ANS="Queue(front)["; auto t = _v; for( bool first=1; t.empty()==0; t.pop(), first=0){ if(first==0){ ANS+=",";} ANS += ToString(t.front());} ANS+="]"; return ANS;}/ o* G. c$ z. f5 \. i) D
};, u! c7 f! g0 \
template< class _T> struct __ToString_Category<_T, 5>{ // Deque
( u) }" n5 {% [% q9 ~ 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;}
/ X0 _3 \- Z% e1 s, _1 q7 Y( ]8 N };
& w) B, r2 m, _' x% I
) [% |2 m7 q+ @* o1 @ 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)))))>{};
: k5 T" i' N5 V& f
* _9 A N7 l2 @" o+ V template< class _t> std::string ToString( _t const& _v){ return __ToString<_t>::TOstring(_v);}
8 r/ S# f4 T6 B& b. z5 @4 Y6 n4 E2 R$ m& b
template< class... _H_> std::string ToString_Items( _H_ const&...){ return "";}# }/ C! V5 S; G( l% p2 r
template< class _H_> std::string ToString_Items( _H_ const& _h){ return ToString(_h);}8 Y% Y- o8 N5 e
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;}& x" \$ h. X% L+ @! @% T
}3 z* K! O0 u9 z6 G
//} omipusDebug.hpp( J( E8 n3 ^( A/ w& i9 [
1 \8 f/ `( H( A) g
28 V; s* H4 J9 p5 Y
3% t8 L( g; Q% |1 [8 ~. m
4: E" |8 q: d* A- @; I3 ]' J
5
8 Q/ S9 k' A1 c2 b' S6
' M+ K' l3 w7 r1 L* |( l70 \& _3 K: e$ J+ U F+ c
8' j% l& l4 \1 m' K3 ~
9
& U5 A, j; H; B4 i/ Q7 b$ a2 b10
9 F# X, Y* z3 j: R11$ U% n1 k c+ J
12
. f4 C. Z5 i8 Y7 W' U* `* @, H& d135 ?, @) x) _. H( ~/ i2 o
14* l I+ W% Y' n4 q- [4 q
15. Y% Q# D' z3 ~$ |' Q
16* P7 h- c8 v# o5 Q2 B0 v
17
1 l( Z5 k) I+ P( q* t1 _1 W% j188 h0 F' f) ~+ G& t( V" k; w
19" y: {( N9 _, ^! U z8 Q
20
k; ~9 M1 E7 `21$ G* a1 X7 U4 B7 j- D$ F1 Q1 N
22
+ B( @" E% n- `3 G) G23
! w3 T' k- ?; p. n243 P$ @2 d: X* ]9 |# J5 q
25
, L# D! E# e" G3 h1 t- _26
- o8 H* @% U+ Q+ r& ?$ S* |274 W+ ^; F! Y* ^; Z
28+ D; [" z- i5 N# @7 k. h2 ^2 d4 e
29( B! X: w% V' r
300 K2 J, R9 T H2 h* j9 w
31
* D- I, o% y- r8 N( M32
2 G: V4 S6 v9 N" f8 K* t$ A) _2 V33
3 |4 T8 O7 o1 F' J" P) e* j34' I- U+ `/ x0 t- N0 n
35( Z0 `) E! L, u2 t% ?- F- M' K
36& L4 `: h4 p" j3 Q+ j# X
37
! M( J* {* l) f4 k: o382 T6 H" l! ^9 m9 `1 R0 T( I; K
39, h4 X( J. [8 y c
402 J `% C- {3 @5 ]) J/ w0 n! I( [
41
3 |0 m7 r. R1 B! h42
. y4 R9 X$ {/ _43
7 d$ V, w( b& T! r: x3 L0 ~, Z44
) ]6 R; z p( u8 {2 W" D45
& s" k! d- b: U46
. p5 B+ w6 }) {7 ?& |6 l47
* J1 f" `5 k! M. E6 c2 Y( [48
% x& ?, j q2 F i$ l0 f# P49
6 E( }. l, K l& V5 Y) Y* g3 A' c50
0 Y Q" e" O* ?, H& c+ z6 R# t* ]$ b7 ]# Y51& }0 a' M- Q3 X2 [& d e: J
52
/ C/ t1 B2 R l5 |: Z' g4 f/ X53
5 f1 `& ^9 @: ?% u( N54
, C5 ~, f* f: H8 h558 g% I2 K/ a' ~) M
56
) a9 {+ y9 r; ~5 g6 W1 G' n: N57& S4 ~" c# Z9 \( e3 `# i
58
8 R* m( _* |; b6 e0 _# R+ q+ E59. x: ^+ C6 n' o, c
606 y( i# h7 _7 C! |! g; p# i* V
61
7 K- L! J0 s" @62
: }* ~' s a( n* R63; }+ }( z* w( d4 p+ i% M
64
' L5 K% D7 d* J: g8 ?# `65# L: ~. d% P, J* f- j7 f
66! z. d. K6 p. U2 t7 L/ M9 W' M
67. m2 `2 X% f! X
689 e5 w1 C- `1 y) n) H% |# g
69
1 h0 w8 y9 s. P70& s7 U* |% d, \3 G k H2 @1 }9 W
71
* }; @) \' @/ s9 M, g3 n72
/ u3 i6 w. }3 {8 q9 @4 ]1 x5 d6 o* R73
' F' ~8 I# \6 {: m74
1 {+ A6 j9 P8 b* C/ a, V75
/ g$ I3 C& ^9 j% s, E }76( ^, x0 K, \9 [( C; ^
77; h) s; j' s P+ B3 A6 T+ ]
78
) W( U2 c$ {0 O, M: s' _3 D' Y796 t- |* z! @9 z8 \$ g, \
80
9 {% o9 W8 a0 p8 d( [81
* Z) P3 l R/ N' ]* u1 P82
$ d0 V2 ]5 {/ g( j83
' g# f1 u g- N% t6 A7 j) U# c84! M8 q% F6 q* {& C/ i
85- N) E/ j' A, D" y0 T
算法競賽配置
/ d- O! g! ~$ p9 mQT_Creator* M# [& f+ w! r- l' }; H4 ]1 s
創建一個控制臺應用, 然後在Pro文件裏 添加CONFIG += c++17 (原來是c++11 修改成17);
. H: b. j! q ^& f0 I" L3 n+ P1 h6 ~6 B O& [
對拍文件4 o- t O& j8 f7 ?/ R e
`compare.cpp`( t m. k# m7 a$ S: q
9 k1 E1 W1 h& c. g- d& S; Z# E
int main(){# z8 `# v9 Z! H
vector< const char *> Init{"build.bat generate_data",; N0 e) v, t, W# g3 I0 d
"build.bat supimo",
$ i) Z5 w7 r8 s0 V4 n/ j' ` "build.bat correct"};
0 v' T5 X# v; e4 I% a) m6 l for( auto order : Init){
# f1 E4 e/ I$ O Z. h# u auto errorCode = system( order);/ q* v3 s+ x3 ~# W1 C- v- R8 J7 v+ D
if( errorCode != 0){ EXIT_( order, errorCode);}: [& ^# u) ~- O: ]* \+ f
}3 x) J! i& ~) m- ~( b5 m( r
4 ?0 n/ w7 u& a3 [0 @
while( true){
! T2 Q2 }, B/ S/ {' y static const char * Ords[] = {"generate_data.exe > data.in",, O) F9 N6 b% w" c- W
"supimo.exe < data.in > supimoOutput.txt",
* K r$ D+ ^* {# y- o "correct.exe < data.in > correctOutput.txt",
$ I1 @ O- c% U7 m "fc supimoOutput.txt correctOutput.txt"}; ?/ h5 B; A: ]1 v0 n
for( auto order : Ords){0 z/ v2 Y6 X% m) G
auto errorCode = system( order);
- i9 u, t# G0 W1 i6 v. z' V% H if( errorCode != 0){ EXIT_( order, errorCode);}
& c- J) M% ^$ K6 `* Y2 H }
! R Y: G& v. W* g; A& G cout<< "SUCC"<< endl;
# s, y6 i- |, K5 M) L( N9 e. V8 X: E }
( i0 m; s% o0 h# k
1 [5 V: C8 n l: u8 H# V W return 0;, r6 l$ `0 `6 n. [6 q( c% A7 N
}
T+ }( v1 K! T3 g, }. n: y11 J# B' F& Q- Y) H; C6 _- D
2
8 f. e2 s' G* m( R I3! R; Q. X/ s( T. o/ Z8 R
4
' F4 J# P7 o5 q( i& _$ u5
' @' {5 Q# x2 W. K6
1 C8 f: P; q( z; e1 y: s. X* y- F! X7' R+ _$ X+ S6 L# D! K
83 \( T: H# `' Y- B3 L# m: ?
9
: p* g/ ?$ Y: w ]& Y106 Z5 L4 P2 \& z' C, N
113 |" g2 a% f( L+ ]1 D( \5 v* S% ^4 ?
12
8 u0 L2 d+ M7 g7 B4 c13
' q' @9 R$ h7 Y' G R- Q* k1 I |3 l+ ~9 D14
2 ^# d. \# s# ?8 y# k+ F$ e# `15. v0 m9 z' m- K x
16
3 h4 K( K8 v( k6 s" g0 }2 Z; o0 u0 K17
, P4 M, x- ^: C5 O; s' A+ Y18- |# O7 O+ P$ `5 N/ L
19 G8 f* I+ m% \
20
2 [* n4 m/ B% Y9 `: P21) P7 d* l7 T `6 \3 b
22# V/ c- Z, J7 _ a8 U. j4 Y; Z
23
; M. i+ \# F6 ]# q24
6 F1 a8 y8 V, w- T) O+ h25
& [1 t2 P/ `+ B1 J" m1 f( H& ABat代碼
% i/ N; u; e4 E8 B- U6 i8 Ybuild.bat5 s( y0 [. y! H) p
@echo off
6 J6 ^0 j* H* D# j% ^. q, ndel %1.exe
$ B n" ]# m% e/ F1 u9 hg++.exe %1.cpp -o %1.exe -std=c++17 -O2 -Wall -Wl,--stack=268435456 -D"__ISsupimoENVIR_"
, V5 [+ L' Q F5 I8 i- J6 f, L: {" ]' Y: r% g# y/ }) @/ p1 B* D, x
@DELI;
- f* l" Q3 f/ N% Y5 s
" j$ X, l! B+ J+ S( g' G, Krun.bat
9 B9 E o& L# j@echo off! } x1 H5 u0 U
%1.exe < input.txt
" z1 p/ d6 {/ ]* t* j+ S% N- l v, k0 h* E3 M9 s# L M7 f
@DELI;
. v, d9 k# _7 k; u. S+ ?# D$ @& m2 K) V/ m4 K* \
build_and_run.bat# M7 _" C1 ^" o o
@echo off
7 {- k: ]6 }1 y8 o0 fcall build.bat %1
8 B% R p9 W9 e8 ~: kcall run.bat %1 %2
' i9 k( Y, p& z# J+ o9 V, Z# H1
: s3 K/ x+ C" L* K! u2
8 |, l$ B l4 }/ X& ^0 x3& V) x$ z, f9 p; E3 |6 h0 n7 n$ R
4
% }; J; T2 N0 b: d# a5
' y6 K! }( l6 `% L' ? U0 I8 c6
2 M% {& S Y$ ?8 r7* D4 H5 ?4 Q; d% k5 {
8) t. k7 }5 ~; H) C r9 O
9( O L: p$ Y% Q) U# J- g. F* D. |1 O
10
* m& Z/ h" M8 V8 b. ?" \0 b4 S9 y11
! p# |. {2 t% ]3 q12
: J/ [4 F6 j- Y8 \3 }% }13
A( J {' V( B5 _" K148 L$ h6 d6 b- r
15) ]6 }; H8 Z9 S" \
16! g [+ {% S3 O+ l/ P
17
$ m& Y6 N. |& Y& K% n- {源文件
0 U3 J( m6 L2 p! ^) `, K" C3 r#include <bits/stdc++.h>
8 o& ]. a X5 e5 musing namespace ::std;" o4 i$ Z/ L; G) |
; L1 r/ C# O% ?+ ~$ t/ @" s9 H2 A
//{ ___SUPIMO! c7 Z) n% R7 a6 a
namespace ___SUPIMO{
" K2 [4 @$ s) X3 _9 R//{ Macro6 z% D, C: {+ q& [5 O
#define ASSERT_CUSTOM_( _op, ...) if( !bool(_op)){ std::cout<<"Assertion_Failed(Custom):["<< #_op<< "], Hint:["<< ___SUPIMO::Debug_::__ToString_items( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< ")\n"; EXIT_;}
1 c" F+ a5 }1 I5 ?6 z#define ASSERT_SYSTEM_( _op, ...) if( !bool(_op)){ std::cout<<"Assertion_Failed(System):["<< #_op<< "], Hint:["<< ___SUPIMO::Debug_::__ToString_items( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< ")\n"; EXIT_;}
' p9 {( K) Y, i#define ASSERT_MSG_( _msg)
" d8 V$ C- ], o5 |( x. Z* S#define TODO_RunTime_( _msg) ASSERT_SYSTEM_( 0, "@TODO: " _msg)
[. }+ y) L8 C& N#define EXIT_ std::cout<< "EXIT: Line("<< __LINE__<< ")"; std::exit(1);
, P/ U" m, b8 J! d#define EXIT_COUNTER_( _max) { static int cont = 0; ++ cont; if( cont == _max){ string str = "EXIT_COUNTER(" + to_string(_max) + ")"; DE_(_str); EXIT_;}}* p: y# ?( g* M+ U( N
#define FOR_( _i, _l, _r) for( int _i=int(_l); _i<=int(_r); ++_i); Y5 b; B; D8 Y& a
#define FOR_R_( _i, _l, _r) for( int _i=int(_l); _i>=int(_r); --_i)
# t- C3 W! W3 x, }; B8 h#define DE_( ...) if( ___SUPIMO::Debug_::___IsInDebug){ std::cout<< ___SUPIMO::Debug_::__ToString_items( __VA_ARGS__)<< " {Line: "<< __LINE__<< ", Msg: ["<< #__VA_ARGS__<< "]}\n";}
1 ?( _2 r6 @0 @# [1 [- b. }#define NOTE_( _str)
3 h( C: q) J, V$ u6 n//} Macro
4 f4 m/ {8 t& H+ i1 Q5 W5 I0 h7 E# D2 k2 I8 m* e
namespace Debug_{
' i7 u; F6 V1 L9 S/ i- R static constexpr bool ___IsInDebug = 1;
; e( L. D+ Y0 v5 h. {2 L2 K template< class _T> string __ToString( const _T &); string __ToString( unsigned __int128); string __ToString( __int128); string __ToString( bool); string __ToString( char); string __ToString( const char *); string __ToString( const string &); template< class _T1, class _T2> string __ToString( const pair< _T1, _T2> &); template< class _T, int _N> string __ToString( const _T (&)[ _N]); template< class _T> string __ToString( const vector< _T> &); template< class _T> string __ToString( const set< _T> &); template< class _T> string __ToString( const unordered_set< _T> &); template< class _Key, class _Val> string __ToString( const map< _Key, _Val> &); template< class _Key, class _Val> string __ToString( const unordered_map< _Key, _Val> &); template< class _T> string __ToString( const multiset< _T> &); template< class _T> string __ToString( const unordered_multiset< _T> &); template< class _T1, class _T2> string __ToString( const tuple< _T1, _T2> &); template< class _T1, class _T2, class _T3> string __ToString( const tuple< _T1, _T2, _T3> &); template< class _T1, class _T2, class _T3, class _T4> string __ToString( const tuple< _T1, _T2, _T3, _T4> &); template< class _T1, class _T2, class _T3, class _T4, class _T5> string __ToString( const tuple< _T1, _T2, _T3, _T4, _T5> &);
! u+ v1 k3 E3 B3 b3 z% [ 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;}
" E2 L$ u f$ B" J2 z' t} // namespace Debug/ N( o3 _! F. M1 M8 Z% v
! `! J% i! |- I# a5 D' K
//{ Type0 }$ ? }8 ^8 R1 k# j7 z
template< class _T_> using Heap_small_ = std::priority_queue< _T_, std::vector<_T_>, std::greater<_T_> >;
7 h, m+ `8 ]% f `, q$ h2 e$ }
* c/ P% [" u, Y4 t bstruct Double{7 m& s! Z: z7 O0 S- Q, q9 \
using __Type = long double; __Type Value; static constexpr __Type __epsilon = 1e-12;
' ^9 s" j2 ?/ j" u9 ~ 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;}
+ M9 v* o& z+ \& @4 | 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);}
$ Q- M `! z y+ z) x2 y4 W; m+ Q 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;}
: e+ |0 i6 N7 d6 {1 P( J}; // class Double
# q" M5 J8 A% L2 j- I; k
, A$ e+ g& s. ]# q% Ftemplate< class _ModType_, __int128 _Mod> struct Modular{
. x% n' j% D, p* `6 f+ m/ y+ J ASSERT_MSG_( "_ModType_必须是{int/int64_t/__int128}");
& P3 C: G E* A using __UnsignedModType_ = std::conditional_t< std::is_same_v<_ModType_,__int128>, unsigned __int128, std::make_unsigned_t<_ModType_> >;+ Y7 s- w. E% l7 j7 o; m+ B
inline static conditional_t< _ModType_(_Mod)<=0, __UnsignedModType_, std::add_const_t< __UnsignedModType_> > __Modular = _Mod; __UnsignedModType_ Value;
* @' J6 X5 Z! i9 P# F# h7 v Modular():Value(0){} template<class _T> Modular( _T _v){ _v %= (_T)__Modular; if( _v<0){ _v+=__Modular;} Value = _v;}
1 b) M' V+ B: u5 T# Y inline static void Set_mod( _ModType_ _mod){ static_assert( ! std::is_const_v<decltype(__Modular)>); ASSERT_SYSTEM_(_mod > 0); __Modular = _mod;}6 t" j+ S( ~6 a% b8 g
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;}7 i. [5 h; T% ]% G+ S9 Y/ N7 J! ~2 B
}; // class Modular6 h q6 n* E( j$ r4 E& o
//} Type
$ B2 v. L! T7 s2 b$ K
- ]4 b; V, L9 P# m6 c+ cnamespace Integer_{' J4 W: u6 }( _2 K5 a% H1 p6 M4 v
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;}
7 N& O. x$ |. g0 p r# E+ D+ p 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;}
: J5 x6 C6 l0 B+ E# ~ W 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;}
- t8 r2 d4 B, Z9 A$ \- B template< class _TypeRadix_, class _TypeNum_> struct Radix{ // `TypeRadix: 每个进制的类型; TypeNum: 所能表示的最大十进制数的类型`;! \ W1 ^- [4 U P; `7 \
std::vector<_TypeRadix_> __Radix; // 比如`Radix=[2,4,3]`, 那么所有的数为`([0-2), [0-4), [0-3))` 即表示的十进制数范围为`[0, 2*4*3)`; (Radix累乘值的大小 就决定了`TypeNum`);
- r0 G2 c1 p& N8 C c, h$ A) F" k std::vector<_TypeNum_> __SuffixProduct; // `SuffixProduct[i] = Radix[i]*Radix[i+1]*...`;
4 C, c) Y7 @! w 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]);}}
/ x; x; M' a/ W! H/ d& o _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;}
: y* K- Z/ T- ^% U 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;}) H/ t- W4 [, j0 }
int GetBit( _TypeNum_ _num, int _ind){ NOTE_("`ind==0`是最高位"); ASSERT_SYSTEM_( _ind>=0 && _ind<int(__Radix.size())); return _num / __SuffixProduct[_ind+1] % __Radix[_ind];}; R4 T0 G2 q3 p/ y8 z0 X4 r$ W* D% ?5 _
void SetBit( _TypeNum_ & _num, int _ind, int _v){ NOTE_("`ind==0`是最高位"); ASSERT_SYSTEM_( _ind>=0 && _ind<int(__Radix.size()) && _v>=0 && _v<__Radix[_ind]); _num += (_v - GetBit(_num,_ind)) * __SuffixProduct[_ind+1];}
9 N( G x6 V3 A* X0 P" K! ` };
$ {+ L( O7 F3 ]0 ?9 |1 m; } namespace Binary_{
+ t4 c* q1 A; z8 o( 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;}# f* A) T/ V9 K" r
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;}* @4 ?5 c t& U( z" Q
template< class _T> void SetBit( _T & _num, int _ind, bool _v){ if( _v){ _num |= ((_T)1 << _ind);} else{ _num &= (~( (_T)1 << _ind));}} j! `& A5 A/ ]4 {1 P6 I, L2 Y
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);}
& n6 c$ y% G9 N' x" E1 ^; G template< class _T_> int Get_lowBit( _T_); template<> int Get_lowBit<int>( int _a){ if( _a==0){ return -1;} return __builtin_ctz(_a);} template<> int Get_lowBit<int64_t>( int64_t _a){ if( _a==0){ return -1;} return __builtin_ctzll(_a);}. Y1 }# r" {# w3 D3 h' j
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);}
3 ~' M( r# r6 t4 y$ v& u9 h9 M 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);}0 W! \8 X; r! T( `* w
// #枚举二进制子集#: `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]` 一定*严格递减*);! H) ` z) \. ^
} // namespace Binary! h9 g5 `9 ]$ F$ P, X& Y6 m. c. t9 ]
} // namespace Integer& v0 i' C4 N8 f* [. |2 s
, ?9 y/ r& q; g8 h! E$ s0 enamespace String_{
P! P0 z' B4 t1 A9 r 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);}, C6 {& o) V& V8 G: T; j: \9 i/ W
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;}}- |0 ]' ^) w# O ^
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;}
}) b+ u/ z3 |. b W2 B} // namespace String
. a+ `6 |6 E/ ^8 R' B+ e9 J. i2 \1 j+ m% z U
namespace Random_{
& |& H7 X3 W4 y' v4 P4 J std::mt19937 MT32( std::chrono::steady_clock::now().time_since_epoch().count()); std::mt19937_64 MT64( std::chrono::steady_clock::now().time_since_epoch().count());9 j2 f0 p) x/ H
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);}# w! V& {: s, i: A& {( z
} // namespace Random
/ ~4 i D4 v& `) Q$ @, X) z3 [$ @* T( h& b! ]( K+ O; Q
namespace Object_{" j- J; M! h0 w a3 z% c) P: l; }
const Double Pi = std::acos((long double)-1);; {, r1 C6 v' ^2 ^7 \7 N. `
template< class _T_> struct __Int_0x80; template<> struct __Int_0x80<int8_t>{ static constexpr int8_t Data = 0x80;}; template<> struct __Int_0x80<int16_t>{ static constexpr int16_t Data = 0x8080;}; template<> struct __Int_0x80<int32_t>{ static constexpr int32_t Data = 0x80808080;}; template<> struct __Int_0x80<int64_t>{ static constexpr int64_t Data = 0x8080808080808080;};
1 E, j% l7 x J* k& J$ @ template< class _T_> constexpr std::decay_t<_T_> Int_0x80 = __Int_0x80<std::decay_t<_T_> >::Data;
* I4 b5 n& j$ b# U6 O, h1 p template< class _T_> struct __Int_0x7F; template<> struct __Int_0x7F<int8_t>{ static constexpr int8_t Data = 0x7F;}; template<> struct __Int_0x7F<int16_t>{ static constexpr int16_t Data = 0x7F7F;}; template<> struct __Int_0x7F<int32_t>{ static constexpr int32_t Data = 0x7F7F7F7F;}; template<> struct __Int_0x7F<int64_t>{ static constexpr int64_t Data = 0x7F7F7F7F7F7F7F7F;};
, b# I% @7 N R5 @3 I template< class _T_> constexpr std::decay_t<_T_> Int_0x7F = __Int_0x7F<std::decay_t<_T_> >::Data;* t; g/ w# ^% K/ @
} // namespace Object5 D& m" n! n# d2 {! n, e9 K
* R' a* h" E. x1 w
namespace Function_{
1 S) L; q, k' n+ r 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;}9 [2 Y d @ n& 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);}* Y8 l6 A; {+ ^+ a
template< class _T> bool IsInInterval( _T _c, _T _l, _T _r){ return (_c>=_l && _c<=_r);}* V! n- ?0 ?) k- o+ I$ J
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;}
' c+ G1 d" |/ G( ^' U0 N} // namespace Function
, J( @: w4 ^2 \2 b& o
7 ~" ?6 M/ V; f; x( L+ F: }} // namespace ___SUPIMO
2 J+ P7 ?; o! n0 Q2 V+ I* Y0 Z2 h' v6 @( {* F# `$ S# G, ]$ g* v
namespace std {
. v% h6 r# E& S/ D template<> struct numeric_limits<___SUPIMO::Double> : public numeric_limits<___SUPIMO::Double::__Type>{};
, e1 v% U6 a! h( ^ template<> struct __is_floating_point_helper<___SUPIMO::Double> : public true_type{};" q! z) l5 C6 e# O
template<> struct make_unsigned<__int128>{ using type = unsigned __int128;};
5 D/ C* k# j; [ ___SUPIMO::Double abs( ___SUPIMO::Double const& _d){ return (_d>=0 ? _d:-_d);}
5 ?/ ~1 U5 C Z: P1 [}
. _+ F" y, F' a//} ___SUPIMO8 g" l6 d; z5 r: x7 \6 ?+ n
9 M, v9 K; T' {
using namespace ::___SUPIMO;
8 }5 C; y; U4 A3 K4 O8 ?
/ u; g' W4 j" Y! V# b# C8 vvoid ___Solve_oneTest(){
0 E, e, Q9 Y) R9 B
* O0 y' \/ F0 `0 z7 h. P}9 a" B; u3 k; \. _4 R; u
int main(){
& S" e& s' M. i std::ios::sync_with_stdio(0); std::cin.tie(0); std::cout.setf( std::ios::fixed); std::cout.precision( 9);% ~6 c' I, L# b' a' ^9 N' q
/ d8 b2 `5 C5 c
auto ___Work = [](){ // 必须严格与*题目*的录入格式对应;
" C6 d% ^9 x% n% h constexpr int8_t mode = 0;
$ \; H5 t# [4 g" J! y int testsCount;
. ^+ P% p' V/ u4 J3 N' | if( mode == 0){ testsCount = 1;} else if( mode == 1){ cin>> testsCount;} else if( mode == 2){ testsCount = 1e9;}+ i; E. T3 A v b6 G& d
for( int id = 0; id < testsCount; ++id){, d& w$ t: W+ k, x) L
if( id == 0){ // Global_Initialize
# G3 G" h0 O5 O- R% t! ?% ?; @9 v
}
/ G& d) L; i$ J* `( p1 z% W4 t ___Solve_oneTest();
8 C' E. v0 u; x& U/ q# _ }: f; n& Z# [! j# @3 P
};0 K8 n8 r1 j: P2 B
if( ___SUPIMO::Debug_::___IsInDebug){& L# W; o: w- B! c' V' ]
for( int id = 0; id < 100000008; ++id){
0 l+ \8 G% {; c/ ?% I2 g string flag; cin>> flag; if( flag == "___INPUT_-1"){ break;} ASSERT_SYSTEM_( flag == (string("___INPUT_")+char('0'+id)), flag);8 ] t. }0 V, X/ ` P1 T2 R
___SUPIMO::Function_::ClockSplit();
+ R0 X) k! `% M6 h1 k( K std::cout<< flag<< ":\n";
% a* S3 [6 K: s7 Z7 U d7 G ___Work();
/ ~ u8 ], m! Q# { std::cout<< "\nTimeElapsed: "<< ___SUPIMO::Function_::ClockSplit()<< "\n\n";
2 D' D6 J1 G: K3 G, Y" F. e }
b* [0 ~- Q: l2 o9 v. g }
; ]1 d$ M5 i0 @6 I else{ ___Work();}
2 w, {6 ]0 [/ D% Y# h, C/ {$ n
# B+ Q+ x/ J3 o3 b' d2 ~1 y return 0;
4 `* V, `: H% \" Z1 |7 C} // main. D2 ~% B$ c1 e$ M( c: H/ m$ X
1 k) a, `- O/ O; T) Z
namespace ___SUPIMO {
) o$ i4 N0 V* A/ q* W. n namespace Debug_ {
+ z$ s( Z* ~* d) M6 g template< class _T> string __ToString( _T const& _v){ ostringstream ANS; ANS.precision(cout.precision()); ANS.setf(cout.flags()); ANS<<_v; return ANS.str();}
# {/ }. E, ~' x: N6 [- c( T 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+")";}
3 m) w! ^0 ]1 A, @2 f; a/ V 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+")";}
8 L5 c7 g6 \2 b' Y string __ToString( bool _b){ return (_b?"true":"false");}
; V3 i8 {: Y- z; Y- @% b' p, h string __ToString( char _t){ string ANS="'?'"; ANS[1]=_t; return ANS;}
% m3 Z: V- i+ f2 _, p2 v# v string __ToString( char const* _s){ return string(_s);}
& i$ ^' t' b! N7 o. o U string __ToString( string const& _t){ string ANS="\""; ANS+=_t; ANS+='\"'; return ANS;}0 i4 Q9 {. f4 b1 ?! o ~
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;}
* C! z( i, j: I3 s2 ]/ U' ?" [ 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;}
' y6 R# h; F2 q6 y4 }3 g) A6 B 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;}: x3 L8 W5 n) i' K
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;}
$ w Z& @' F( \/ i0 X& | 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;}
, B: k8 r! M0 X+ r6 @. Q* T' ~ template< class _Key, class _Val> string __ToString( const map< _Key, _Val> & _v){ string ANS; ANS+="Map["; bool first=1; for( const auto & i : _v){ if( 0==first) ANS+=","; if( first) first=0; ANS+="("; ANS+=__ToString( i.first); ANS+=":"; ANS+=__ToString(i.second); ANS+=")";} ANS+="]"; return ANS;}
1 Y: S$ _3 s( y/ V6 z4 J t l/ I. \ 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;}
8 [ Q' Z# J; r 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;}
( J2 |$ 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;}
, J1 `) F# l/ w' ^/ U8 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 L1 U+ z8 b* M3 i8 K 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;}! r7 p) {1 Z1 h
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;}6 X1 `/ l& m0 z5 D: r9 b
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;}
- A. A( n& ^# h8 g5 @( } }. p- |, B2 I% J6 z
}
1 T: W' g3 h( I. l8 j$ A1
$ M: Z" @4 Y: G' i* C2- {5 |4 ^" ^$ Y1 H: b
3
* ^( M" j! O" |; A. e( M) Q4* ^* Y5 S# g+ T# y6 [. c9 v
5+ L5 S* V1 q; s4 |$ Z' r, ~7 {* X
66 Q6 k/ P* e7 Y+ O7 F: j% X( z- ^
78 l6 M, [& J+ K* Q9 d" R) n
81 i. |$ j! P& J9 v2 Z9 Z- ~
9
4 B+ ?6 u. q4 @% g! |; f! t9 Z10
4 f8 A! o6 w0 t. f11
3 L) s+ U8 t" ]! ]3 Z6 S12
4 w* |& Q, I9 O; K4 B13
5 \8 t {0 T1 }14
5 {( S3 e4 T' F. B15
% C0 u8 L1 ~, e% z16
) P7 u$ ^" x- Y p* Q% R1 p17
& T# u3 d2 v" D% @4 b184 }& D$ Z" O; q5 ~
19
) M$ v' d- O. O2 G8 I( a2 z' i202 d# U$ }2 Z" C7 [- C. D
21
: w4 `7 E7 U* s22
3 W# v, n9 D3 H: ]% E23) q+ Z2 M2 S) f1 |3 `
24
: t1 b7 N7 S3 m0 k# D( {25
8 f- T. P; N9 W6 X l6 c, s: f26
5 O3 w4 X& ~3 C: E6 s6 i0 q3 [27
6 |' v( n' E) r: \; a8 b, j* m28
8 X3 P8 q* D. ^4 C29# O" d8 _% L. M& X$ s3 [" ], z8 u& C
30
7 n4 R/ R7 c8 u _1 L" ?9 M31, Y& {* Q/ c$ W3 r
324 y1 I1 ~6 x' {
33
' V. j0 o( x) Z4 M34
7 a8 ^/ z7 d* n# Y9 R' f35
9 r1 P: W$ K9 U. T7 {4 _1 }36' T5 I3 C d) k$ @
37* k+ D+ U' f4 [4 ?6 L3 `* M
38( J7 K) j$ r( m6 o: w
39
6 `7 p/ ?0 m; `/ M3 w9 n7 r40
4 j4 w) t$ g8 D, s% P# ]0 f {. t41( }9 `- @ n! H# V' ]5 F/ e9 b
42
' S5 p `' j' y0 C43
0 j/ ], O6 \/ F! g( h8 {44" j: m8 k' x6 x* ]' C6 t/ y5 u
45
# H9 ^, F+ ^/ a$ i/ s46
( F4 P8 w& C$ r& E/ b& R" V47/ J A6 ]* s/ f3 A+ ~( m. x
48
' C4 ?0 ^- ]# V. c5 v4 { ]49
) k( o8 `+ P( S50
7 h: _- E+ W/ M( h- ?8 {0 ^0 g511 w$ }0 {6 Y) Q2 b/ t; a( I( I& I
52
; f# C6 o; A ]0 A; ?+ V" t9 P: f53
: W2 }) |8 B4 w9 c54$ Z( M' m* [$ F6 E: { V# Y5 `& W
55
# ?+ G1 R3 @& |6 B3 [, x6 i56
( Z" |0 |& R5 g- a9 ~/ d Z! U1 W57/ [% o/ l9 K, X5 E! G
583 ]- \9 q9 x# {( o/ K7 \2 F9 ]
59
1 R6 B9 q ~! |( ~7 ~60' y, w7 [! F9 o' j; w
61 t: w* L1 F& B( x1 \
622 @) r) \ B0 I3 i, u- x! S
63
& o0 p' _, b, g0 o" o. j; g646 ^# i Q7 f$ [1 c6 h; e- g, E) G
65
- n0 m% U2 n: ?: o( V8 y W66
, J; F; S# S0 J) S z# |% B67+ z! ~. L0 j z: ]* c* C5 \& A
68
+ i" o" ?; M+ `2 f9 [% b, u' `+ F69
1 u' Y& V8 U! T2 t; u70! j+ e+ k: h7 G- C5 h4 t
71
" e! z& B$ H" e, C% I8 C4 q72
9 J. u3 |# ?" d3 G7 K, [1 ^' \' K L732 g; b' v+ E5 [( W8 \4 F* s
74
# X$ {; j; k! y d" p75
9 s0 `# Y- D. w6 \# ~" ?76- O/ T; o s5 ]; [7 z& y
77- @1 _2 G E* P
78) K$ c( d* E0 T! k. X% r: b" N
79
, y4 F$ O2 u3 o& R0 ?8 O) R1 N809 ?' j) o9 c: X' @4 S7 w
81
1 s% E, m7 w( o+ L/ m& [82
1 L3 B1 n! Q! o" u Y8 Q* O! h83
" j6 ]1 c# [& G5 _84
& h+ T, ]" k$ M/ u2 a, a0 a2 ]85
1 e/ v, Z: H% }+ o4 s8 [; h86) a; {. V! n" u& `9 z) ~' E
87
* L+ q# E5 |$ u; q, _88
$ K0 B: S( b4 L5 e1 o4 r: g891 c9 H) q% `+ C# ~7 p2 `
90
1 G7 T- f W9 [' R/ ^: Y7 D914 B. p" s. ~1 J8 f6 Z
92
& |+ J4 o, {8 d( t8 i( d93
: L& e' X7 u0 s' F944 `: P; f, x4 v( a5 M. T- z, j
95
# M* P( m; Q. R5 }& {- \5 H, m/ S96
- [; d! l% _. Z9 V) B97
/ ?' e+ u, g9 ]6 f985 Q- ]) q. _* v& U6 V( i- [
99
) h) X! }" S( Z+ U$ G% ?6 l100
; \" u5 T8 n) }- w: o. @1012 ]; H" X2 C0 @" u
102: \2 x: m: m4 {% Q
103
[1 X, I. H" Z* L3 s9 Q104% K9 F1 Q' p, H
105
7 Z5 m* x! Z$ G% g. }$ g' X+ N106
5 k( z7 R% G7 _ S107
& y b2 T4 `+ ~5 s* a, m+ k108
, j+ W6 Q/ @3 b! @1 X3 `* @109
_' \- e# }" i! {2 y1108 A) X$ Q7 q+ U3 J0 r. E/ `' F
1112 }. Z+ _2 I$ x- n1 S
112) T( D' L" [- }1 q
113
' K# o' z+ H! o114
4 k6 h0 I7 l& S) i; t115
: N1 p: R3 M1 P; q& A; T116+ A9 M5 K, z7 q
117
6 P' y7 H& r' m! S, `7 m118( r9 X6 m# }- J* J+ E2 [3 J' A
119
9 N8 T' W% G* y4 B$ u120* r# u# V, V" Y
121, h A j" S; H5 z1 Z: O6 ~3 Q& H
122
?: q; R; c/ ^! F# U2 B# E8 A123
% W; b) {, J" Z3 h8 [124: }+ Q% u* s3 G
1258 a8 G! w5 b% E8 d* R
126
: T+ q' A, s6 b. {& r9 J127+ ?" x% x y! b, l/ d$ w* M
128
9 z) z0 ?9 D, m129
" F! p8 q. V$ ]2 Y9 U, s: w130& e& C+ A6 |$ n8 A' }! o4 r
131
, H4 m1 ?% }7 H$ g8 L5 c. I132
9 ~$ t! a* U( h8 B133
$ v. Y' T& e+ @5 y134
- C: B L* M( v, A. a1351 E. F0 s- [) k# g8 ]5 u" G
136
/ u+ g- ]0 o) D5 S* `1 Q137
' I6 A$ p" H7 f8 u138) ?3 p. l# v' l& c/ R0 i
139) ?2 m7 f ?$ s9 j# i) y
140
$ ]: F9 I+ U) R& C9 _141" {4 S4 }. o O: q
142
3 [* e# p6 x Q143
1 f1 s8 U; A) a& ?8 l144
3 m0 x- H2 g3 N( Q7 M Q: T$ j145
) E# Z% S+ {2 t; X3 @# V; j146
& M3 f$ n1 k9 k" Q/ {3 P9 F1473 `6 {! l4 H" i$ E8 E% q
148; a8 O0 H& I n o5 O4 w& ?
149
& O7 D: ?) i/ \: w150
9 B9 [0 w$ j# u: @6 T9 S: k151
6 P \" y/ N" }* F6 l1528 j4 s, m. X! p+ S) s
153
. w% w" _( n3 t( Y: x0 c1 A154, r7 x0 j( g) K- ]# b
155. ]& N9 d2 ?/ r3 A
156 A1 }5 `* I" X1 K7 u. D4 `
157
% @; C0 g% c. L/ f158. L. }9 x1 @8 }% \* P. q$ ]
159, ?% k& a5 q: ?. H. T
160. |7 v+ \$ |7 N8 t. R
161( ~% ?9 y3 q4 Z/ N% A$ K
1623 u, B+ c& r5 s P
之所以把___Solve_oneTest()單獨寫成一個函數 而是放到main函數的for循環裡面, 因為: 當我們要進行特判 比如if( N==0){ cout<<"YES"; return;} 這裡的return 就是結束當前測試, 可是 如果你放到for循環裡面 你可能認為 那用continue不就可以了? 錯誤, 因為如果你內部還有for循環 這就出錯了 即此時continue不是對*外部的for循環*生效; 所以 必須要寫成函數形式;% p0 F; a" u' B
f4 L/ { v- b4 p i+ gGlobal_Initialize* g5 \! u" R; A% Q' K9 U! J) R) }
专为力扣设计的, 即全局(多组测试数据所共用的)数据的初始化;
9 u- ^: f; A! M/ ~( }& L. J5 o h" Z( d9 f! _
String, M# L. F; ^( R1 ], M' k( p
Split的答案 一定不会有空字符串;
/ F4 G: E6 |* ~: b他是从前往后贪心进行的, 比如"xxx" 以xx分隔, 那就是[xx] x 即答案是最后的那个x; 比如"xxxx" 以xx分隔 那就是[xx] [xx] 即答案是空的;
! z- w: w" J4 F$ O. a) V
) W) a# W; e1 W- N& U9 `6 G2 c@DELI;
4 }& l3 v: G! U! f. o
4 A- x, L2 @# t4 tReplace的本质 就是Split函数, 即比如你Split得到的是? X ? X ? (将X替换为Y) 则答案就是? Y ? Y ?;
, T( K" u( Z* Q& H5 O- y* O! B. 比如S="xxxx", raw="xx", new="x", 那么答案是xx, 即先是[x] xx 然后[x] [x]; (并不是[x] xx 然后[x] x 然后x);9 V, L9 O# w$ q& g
5 g( B8 e- ]3 f) S! X+ x5 G( D: Z4 x6 nDebug' q6 n2 Z8 m! A1 C" e, q2 k- p
if( ?){ Debug::__IsOpenedDebug = 1;} 和 Debug::__IsOpenedDebug = (?); 这两个 是不同的!
2 a, |( P- g0 V前者: 他是在特定情况下 打开调试, 但是他不会关闭调试; 而后者: 他要么会打开调试 要么就关闭;. V" T- ^0 {& ^# R9 u; y: ~
前者 通常用于 针对某个子流程而调试, 比如... [T] ... 最开始我们关闭调试, 然后到[T].入口时 打开调试, 然后到[T].出口时 关闭调试; 即整个过程 我们就调用了三次IsOpen = ?命令; 这通常在DFS时 使用的较多, 即符合某种条件时 进入某个DFS分支时 打开, 然后回溯回来时 关闭;
) n' `0 b& l& d) D. k而后者这种方式(即不停的根据条件 打开/关闭调试), 一般在非DFS的场景(比如FOR循环)里 会使用, 比如只对所有奇数进行调试;
) @! v: b* J; g! z: I4 G: Y即前者 他是针对一个连续的子段, 而后者是针对一个序列里 满足某条件的若干元素;0 b0 C' c4 M- U
) v' c# p+ T- X! n' x@DELI;
* r! r. j) P1 A- x) `: w
. M9 p4 S& Z0 Q' j4 b有個疑問: 為什麼要把他轉換成string 而不是直接cout輸出呢?
4 |! ~ T7 h/ H- u; P. 可能是多了一层封装? (但毕竟你这个模块 就只复杂Debug输出啊 有必要再多封装一层吗?
; H" f. x ^3 X0 |" m. h2 o
7 C3 s6 z3 L) k6 [* g@DELI;
+ m3 z, U+ p% V; U, Y, G0 F! f6 U$ q: m4 r& m5 u
INFO_里, 不可以对#__VA_ARGS__直接用,逗号分隔, 因为他可能是INFO_( F(a,b), 3), 所以你还得判断括号;
; W1 a, W% b- g1 Z; V; x$ G; ?$ c+ ^5 _7 O9 r3 o5 q/ \. I4 R
@DELI;6 a7 K7 F! {& `( o9 u3 g5 ~$ R1 f
" @, K5 x* I' \9 [6 IT A[10];數組類型, 你可以直接輸出DE_(A);0 w. a* Z3 j# b9 Z- o
DE_( (T(&)[5])A); 這是輸出A[0,1,2,3,4];
2 z; W6 r m9 }0 g
5 Y- P; `. S8 Z6 E0 b: w3 Xauto A = new T[2][3] (此時auto == T(*)[3]);6 ^1 B( [$ B7 n1 Y% b
. 要輸出他的所有元素, 此時直接DE_(A)是錯誤的(他是個指針地址), 正確語法是DE_( (T(&)[2][3])*A), 注意 *A的類型是T(&)[3], 但你把他強轉給T(&)[2][3]是可以的;
( ^) H6 m/ b/ q9 k$ ~
$ ]0 o' I* r6 L6 C0 N@DELI;* P! R, h5 U# L7 q6 ^! k
+ n+ Y( @, Y) l8 u6 S5 |" V' {- W7 x
__Debug_list的參數 必須是const _H & _h, const _T & ... _t引用 不能是值傳遞;- e- V/ G9 Z* T, k: t& M
比如對於對象很大的情況(圖 本身都已經1e6級別的大小), 那麼 這已經不僅僅是效率問題了, 因為參數用的是棧空間 這是會爆棧的;' R# z+ ]0 d( e
! r4 S5 O' p! ]4 Z3 i@DELI;# ~& T6 s. W1 E$ N% E; R
5 o$ D! V. R$ { C" @0 \2 {
我们使用__Cout自己的重载函数 而不是去重载operator<<, 一个原因是 对于char/string基本类型的重载 此时和系统的就冲突了 (你需要再单独写个函数使用is_same去特判) 所以 不如就不使用系统重载符了 直接自己定义函数; 第二个原因是 其实把 两者本质都一样 我们自己写个__Cout函数 等于多了一层封装;5 n0 l. F4 M9 i% j" A. A- _
7 `* M+ r1 @7 B' q: N/ g( Z! g
你必须要声明/定义分开 這是為了實現對嵌套的輸出, 比如对于vector< map<int,int> >的输出 他使用了Cout( map<int,int>) 因此 你必须要有其声明在vector實現函數的前面;
0 _ T& Z6 G$ l' O% T8 z+ C& Y
如果是自定义类型 他会进入到Cout( T) 然后调用cout<< T, 即你的自定义类型 需要有重载运算符;
+ e( G4 Z% e' V) j$ A, |0 w+ P: b l- M, R; @( e
@DELI;/ M0 h7 M* \: n% ^
" S! p7 C: A4 n3 } {
__Cout你不需要寫成 像ostream& operator<<( ostream&, T)那樣, 直接寫成void __Cout( T)即可, 這是因為: operator<<之所以要那樣寫 他是要實現cout<<a<<b<<...這個操作; 而__Cout 不會調用__Cout(a) << b這種操作;
% A! k6 w1 `# r j, m. `7 v$ S, ~4 Q6 j
8 q- v, g: L- ^6 G; FASSERT報警宏6 ~) t1 [4 V) K6 G. ?
#如何关闭某个子模块的ASSERT$
. q' Q& c0 H# w7 \对于算法模板A, 他里面有很多ASSERT_SYSTEM, 为了优化效率 如何把他们给关闭掉呢?
' R- x5 }, d/ c$ H" Y N
9 Q ?! |9 P0 D. @# }& G( B5 l#undef ASSERT_SYSTEM_- a, L. S8 i: f) Z1 S6 R
#define ASSERT_SYSTEM_( _op, ...); ^5 Z0 `' F% w6 Z5 Q
namespace A{& }5 G6 M8 \: f+ [% F: F& i
}. J( R9 i6 C+ [! `% [/ d4 B
#undef ASSERT_SYSTEM_ ) Y G9 g6 F5 O5 P t9 q' H& w- z9 g
#define ASSERT_SYSTEM_( _op, ...) if( !bool(_op)){ std::cout<<"Assertion_Failed(System):["<< #_op<< "], Hint:["<< ___SUPIMO::Debug_::__ToString_items( __VA_ARGS__)<< "]("<< #__VA_ARGS__<< ")\n"; EXIT_;}! H* g) N+ v9 q# `( X, `; Y. T
1
" e$ z. Y3 N0 b# |5 d: F2
& c- a2 i8 R# N9 u3
! e1 l. ~4 w: `0 j3 Q/ m4
c& D+ Q& s: K3 ?. i, \5# t! ]- \8 p% F7 ~# \0 S
67 P7 a3 g9 {5 u- a0 `
. 也不可以不写#undef, 但他会有警告warning: 'ASSERT_SYSTEM_' macro redefined;7 W/ p+ q. K/ V( k
* }% e' E p% z# [% p! y! z@DELI;
& k; S. w3 g0 z! d+ ]" `( e9 N
/ u/ O, ?( H) k/ ~( ~8 a9 aASSERT_CUSTOM_: 用戶自己的程序裏面 使用這個宏;5 p: L- K L: f6 i
ASSERT_SYSTEM_: 算法模板裏面的報警 都使用這個;
) N5 L( q, |9 t7 x9 `- M
+ M8 Z9 y4 H$ u$ m( r) N* h宏- w v% h- _: h& O; S( I
為什麼FOR_的宏定義是 (int)_r呢?# C* H# y2 @: Z0 v
對於uint32 a = 0, (a-1)的值 是111...111, 於是for( int i=0; i < (uint32)-1; ++i) 這會死循環的;
' { B" m* |- _1 ]* t' k' o但是 把111....111 強轉為int, 她就是-1, 即int i = 0; i < (int)-1; ++i) 這是正確的;
+ @+ P+ U1 Y( R( c1 U% ~5 a. ^" J
% K+ J/ t9 y& p+ ^7 o@DELI;3 F; h: |. q9 a
+ c: ], Z7 J, w5 ], D這3個報警宏 都有2個模式:4 w' B/ R$ y( [/ Y
1(默認模式):[如代碼所示];- C4 N7 K% q+ G/ N
2(優化模式):[你自己把他注釋掉, 這主要是為了(提高程序效率/便於找到程序BUG)];
; H( K- k% t* S. t' Z( [9 w. 比如默認版本是#define A x, 那麼你就把他改成#define A (void)0 // x, (注意後面的注釋// x是不生效的 預編譯時會被清除掉 即到時候是(void)0; 而不是(void)0 // x;)2 {$ b4 u" n: y9 u3 ]+ T
. F/ E! W9 C5 e% X0 D3 v+ X! U1 `ASSERT_MSG的優化版本 即static_assert(false), 此时在开发阶段就會報錯 也就是你會發現所有的調用ASSERT_MSG的位置, 就可以发现有可能存在的错误;
8 F1 B% G4 s; \# y
6 K3 ?4 W6 P) h0 G `- R& ~@DELI;
2 ?0 ~0 ]) S( l
% E! K- ~& L3 a( @' w. {8 A0 [( \#ASSERT_MSG_( _msg)#5 N# L/ @( _5 K% }# |0 U& h
这是完全给用户提示的 程序无法测试其正確性 但你自己必须保证他是true; 比如取模除法 mod必须为质数, 就可以是ASSERT_MSG_( "mod必須是質數");
6 `+ F% U0 ?! k0 _7 f; F3 Q* _
6 ]) F0 Y6 g9 f a& r. A$ T( r@DELI;
' D% [8 [5 z! F1 x! a; Q2 b- F5 C
3 H" i3 }3 ?% }' ^* p+ \#ASSERT_WEAK_(op) (void)0#
6 B0 W4 A1 ^* R: g" O# Z5 s2 V即使op为假 也不会报警, 但你自己要保证他一定是true 这是为了效率;/ \ \! l0 e) D" r/ d
; B3 y, ^& i3 n& A# wModular3 P/ |( O7 M: j
Modular的設計思想是這樣的, 她有2個模式: 對於using MOD = Modular< T, X>, T必須是有符號int/int64/128;
9 R5 T# n+ w) ]- i9 h1: 你的Mod模數 是不變的const常量, 此時 這個X是常數, 即在編譯期 模數就固定了;$ T8 K/ \' L1 V% d: f
2: 你的模數 是可以改變的, 此時這個X <= 0(你任意設置一個值即可), 此時到了運行期 你可以動態的通過MOD::Set_mod( m)去設置他的值 且這個m參數的值 即模數 她必須是在T的正數範圍;5 l5 _/ ^4 ~4 ` X
不管哪個模式 假設你的T=int 你最終的模數 一定是在[0, 2147483647]的範圍內的 (而不是uint32的範圍), 而且你的值Value 一定是unsigned T類型, 為什麼要這樣設計? 因為 當你進行加法運算 此時 你不需要轉換為int64 她的加法結果 一定是在uint32範圍的;
, j. V4 n9 U& S7 K6 i4 b$ t7 h7 G( O7 ]5 Q/ ^1 q! e: l
@DELI;% G) |+ D0 _6 y& i( s8 X2 k' Y7 e
, g0 N. R9 V' m# Q7 g3 }6 `對於乘法操作, 如果是int32/int64 則直接轉換為int64/int128來進行乘法, 否則對於int128 則執行二進制乘法(她會調用取模加法 是不會溢出的 這就是為什麼你的模數 必須是有符號範圍);
, I! v+ a2 T! v3 p
/ m/ w7 v: J" C- Y0 Z@DELI;: n# V+ z: y% s0 l" v
9 |1 o0 o* `9 q( _4 c( H+ {
template<class _T> Modular( _T _v)這個構造函數裡 你不能對他進行is_integeral的判斷, 因為對於__int128 他不滿足條件(可能未來編譯器會支持 但現在他的返回值是false);
$ i5 E) n% q4 b9 \& P5 [5 K
* q, y1 L0 ?8 X" V- h$ X' r! U, g@DELI;5 M" T! C% j# ]* M8 D
& e7 p9 [) B7 g; _3 i# v( Q# e基本使用
1 Q$ X* N& w9 c1 m+ Q9 I% Y) x) O( b/ G, q( Z# y2 u) y
using M1 = Modular<int, (int)1e9 + 7>;( \/ m. t5 G5 X$ F% ?3 v7 T* b: T
所有`M1`的對象 他的`Mod`都是*int常量*;
4 c! Y0 n* c" |2 [. D
- g, g/ z: [2 c& j+ [$ } n& jusing M2 = Modular<long long, (long long)1e15 + 7>;
, K k( v' U2 ~4 l所有`M2`的對象 他的`Mod`都是*long long常量*;, R! F B8 Y% g( Y! w
2 V3 w: F0 K0 s; k7 lusing M3 = Modular<int, -1>;
/ t, V6 ?2 F/ `/ w+ sM3::Mod = ?; // 由用戶錄入 (這行代碼必須在*運行時* 即放到函數域裡)
, g [- d0 o3 M4 ^所有`M3`的對象 他的`Mod`都是int類型 且等於`?`;
3 H/ r O p2 p
( U+ u4 {7 K$ u2 a' Vusing M4 = Modular<long long, -2>;
- p/ @8 B' u% o: \M4::Mod = ?; // 由用戶錄入 (這行代碼必須在*運行時* 即放到函數域裡), N, L4 R! ^0 q" I3 }" s$ T- s
所有`M4`的對象 他的`Mod`都是long long類型 且等於`?`;" g* j% I. x9 L. w' H9 M) i
. I3 }3 E0 a! o
using M5 = Modular<int, -2>; // 注意此時要和`M3的<int,-1>`區分開來 即不能寫成`-1`, 否則`M3,M5`就共用同一個`Mod`了;
& D3 Z9 r! Y; r8 K1 A) \7 I
" d0 s% R9 a1 j x: F% k9 l
9 Z8 I7 s% U+ R2 Q@DELI;
) M! n$ M, w# _* {3 H. \ W" n7 X! O# E3 S; w* W
T_ Value; // 一定是[0, Mod)范围; 不要调用`obj.Value = xx`(他不是规格化的) 而是使用`obj = xx`;8 Q8 R q$ N. m& X2 c0 [
1
$ q# r, O3 W4 t: y! q. _#除法#
|8 d7 `, N, J0 v+ @0 w调用a / b的前提是: (1: Mod是质数), (2: b != 0);
/ F6 f0 E9 _6 N/ f' }/ x! ^4 e8 I* y* J1 P! ]
@DELI;
% A- M4 C- @+ G! Q& Z6 R2 R, N% X. B' j8 V6 |8 T
#BinaryMultiply#/ Z* m, `, v) X+ g% }0 j8 A
使用a*b(重载乘法)的前提是: Mod * Mod <= INT64_MAX; 如果是Mod+Mod <= INT64_MAX 就不能使用重载乘法了 可以使用当前的二进制乘法;1 x. `) E1 I8 J; n& M# @9 F+ u
! G" k) B( @; ^) v: J@DELI;7 P! N) k) J Z
( D+ C; |) W$ w7 J% W
#__Cout#% v5 O9 y& \* w3 j7 m
这个函数的目的是: 特判, 即对char/string/const char *的输出 重载, 之所以不是放到<<重载运算符函数里, 是因为 如果是<<重载 这些基本类型 就和系统cout的内置重载函数 冲突了;
0 j% y, s; a: c) a. g1 N也就是, 比如对于vector的重载 是放到operator<<里的, 而对char的重载 是在__Cout里;' h' O, _4 X$ ?. j, }+ y( Z
' M( Q/ F: d( C0 _函數
: g1 n$ |+ _* m' [#IsInInterval_#
; y0 A2 A, i* G1 ?: \- U. IsInInterval_(c,l,r, true): 判斷是否滿足`c>=l && c<=r`, 即在這個區間裡;. U3 @# S: a) x! E( X0 |
. IsInInterval_(c,l,r, false): 判斷是否不滿足`c>=l && c<=r`, 即在這個區間外;
# _8 I6 |' c3 k# @/ T- n1
9 E3 a5 P* P, C. F9 L* `2* \7 W, f3 _2 m" Z
3
& D+ |8 U4 X+ B1 l$ qInteger, C* S( \ @$ }5 u
GetPowerRoot( a, p), 比如令T = a^{1/p}, 则返回值为T的下取整;
/ N0 s/ V0 _ ?" }! t; z7 z# p9 V3 X% E
@DELI;4 y3 Q# T& Z; C8 `1 X
- T3 I" z8 \& @
VectorToInteger和IntegerToVector是互逆的;. X; N/ C5 y x* O3 G) _9 L
數字的高位 就對應 Vector的開頭; 這樣設計是因為: 對於一個整數321 我們通常是從高位開始閱讀 因此高位對應vector.front();9 C* O; K3 h. a+ b9 A. l
. 比如, 整數321 (3是高位 1是低位) 她對應的Vector是[3,2,1] (3是開頭元素);
4 V S: B+ I2 {/ N2 |) @" t
7 Q$ _; X6 M' ?5 B" n& D2 |@DELI;! u4 N6 d$ D) c. G5 o
8 I3 |9 L- ?& k0 m# d" O% E; i6 Q
使用该模块里的任何函数 都是谨慎, 最好就是在调试期间调用, 你要充分考虑好他的实际效率问题;( ~8 _, t/ o( Y9 V
比如VectorToInteger( {a,b,c}, 5)这个函数, 其实 你可以自己手动写成a*5*5 + b*5 + c, 没必要去调用这个函数, 因为此时你已经得到了{a,b,c} 他的长度是明确的 去调用这个函数 反而效率非常低;
$ v/ ^0 _& n3 Z% w: ~0 W9 Q
$ \) Z( h: h1 T7 A/ X@DELI;
5 f! r& B# R; u+ j9 W( ]5 S
! K! ?, O; W& @& H/ z3 ` Zvector<int> IntegerToVector( _T _a, int _len, const int _radix);! J7 s' Z- k! N: q0 b) \0 b
比如a=10, radix=2, 他對應的2進制表示為1010, 那麼此時你必須保證len>=4 (否則會報警);
- V$ R" |$ @5 f8 G) g. @IF(len==-1):[答案為[1,0,1,0]], @ELSE(len!=-1):[答案為[0...0,1,0,1,0](即前面補充前導零 答案長度為len)];# z1 Z- b. p, R
6 U5 t, J0 g: @# b1 Q9 z1 L8 _@DELI;# o. [/ F; k0 a- d& h! p
& K. b- u5 e* ]! j4 D
Sqrt( a, p)
* n7 @* g: u7 A! S要確保a>=1, p>=2, 假設答案是浮點數b 且返回值是b的下取整;
9 E0 D4 \$ y5 T1 Z( g這個函數的主要目的是 判斷a是否是p次冪 如果是則返回其p次根;1 @! s! I+ D% K3 s" y% m
. 由於b = pow( a*a*a, 1/3), 此時b可能是a-1/ a, 而答案是a, 所以要判斷 是否b+1 == a;$ g0 L1 b: P& Q H$ Q: Z
i3 K2 G# w. E% T- \
@TODO$ s6 `0 y* r9 G2 g: ?" a) o+ `$ g) e/ m
Modular里面, 我们用unsigned T来存储结果, 但实际上 你的取模值 一定是[0, T)范围的, 即只使用了一半, 这是因为 当涉及到+-时 此时不会溢出;
! Q( t) J: v' c& f& W7 \. 但这有缺点, 当你Modular a = -2时, 此时构造函数是-2 % 5 他会变成int % uint -> uint%uint 即-2会变成uint 这就出错了!!! 因此要写成int%int;
, n- j: u5 H" l. m' {6 ]: B最好是, 你就用T来存储结果, 当相加时 他虽然会溢出 但其实他还是正确的! a += b; if(a<0){ a -= Modular;}就可以了;
& @( I; p7 s" j" |& V' L
, b! t! x% i* p# f错误+ b# @% Y6 N% h {4 e% e
is_floating_point_v< Double> 他是等于0的! 因为Double是我们自己的自定义类型;
& U, `9 T5 G0 n9 X你可以写以下代码后, namespace std{ template<> struct __is_floating_point_helper<Double>:public true_type {};}, 此时 就可以了;
4 m0 L3 `/ s. o: J& y1 f* Z$ c( v5 M5 e1 q- E
算法模板编写规范
% ?. H, C2 |% W* v错误
P8 [* B! o e8 Q1 H% m模板类 不要写构造函数, 因为我们可能写到全局域里 ST s(而不是ST s(??) 此时不能有参数;5 L" {5 r& c' Q7 d, m$ w9 K
" l0 B5 r# C7 k# n" U7 e7 p/ n@DELI;
- k) I% x) `! z; ^& i- c5 u
; @* \0 G" @5 a# a不要写namespace ST{ using T = ?; vector<T> DP; void Work(){}}这种代码; 这样会导致ST是一次性的 即T是唯一的; 然而namespace不能加模板;
$ I& c8 [% V9 F+ m8 C* q; I一种做法是: template<T> struct ST{ static vector<T> DP; static void Work(){} };, 但这样有2个缺点: (DP需要在类外定义 因为他是static), (由于ST是类 而实际上 他里面都是static的 不会用到他的对象 这就违背了类的初衷了);
+ Y8 [# \' y" ^, s最优做法是: namespace ST{ template<T> vector<T> DP; template<T> void Work(){ 使用DP<T>;};
+ a0 E+ z$ K2 ~5 U1 Q$ {$ q9 ~- H9 g5 Z' p: Q
性质/ D2 N0 h5 ?: d2 f
模板类里放大数组constexpr int N = ?; int Arr[ N]; 等你用到时 再把?赋值, 这种方式 他确实是效率比vector<int> Arr要高, 但有个缺点是 你到时候的类对象 就不能放栈空间了 需要是static ST s 否则大数组就爆空间了;
, S! B' k& s1 U0 r' E; X
4 X6 y# v5 C; u# Q@DELI;$ {! k# j" j; }+ T& S9 v
2 `6 f+ u: ~! X5 s
不需要寫一個TODO_STATIC_的宏, 對於靜態的@TODO, 你直接寫成注釋即可: @TODO: xxx, 然後實際使用時 再把他給注釋掉即可;
( p5 @2 B; }% U( m' K4 a
5 K1 f5 K8 Q( ^* q1 D' S1 j@DELI;
' N9 N; c; v! u8 ?) W/ } M4 A t$ N/ ^) N4 ^% K# f* f
#讓某個函數 必須在程序開始後執行一次 且只能執行一次#+ h$ z3 @) c, p. \" e
3 o2 n2 j9 B( B$ j
void Init(){
3 |( d: m( P, E* v2 A EXIT_COUNTER_(2);* L, x% p0 B7 \) G
}$ |$ Q# Z0 d5 T' s1 V
@TODO: Init();
6 L5 t" \# m+ t: ^: r1
" P9 b5 b" {5 b% X/ L2
8 V) ~# Z1 w8 C1 \/ a7 b$ N3/ V# S; f( A0 H( V& ]$ u! |
4
+ X/ b- F6 G* R! d這類函數 通常是不可以有函數參數的 (比如篩質數函數), 也就是 她的參數 是根據題目的最大數據範圍 而不是錄入的值;
7 v" E N' i7 J, m* o) b& z( b9 E1 H- U9 R- D/ M
不要用__attribute__((constructor)), 她是報錯的, 因為他不是在運行時執行的, 而我們的需求是在運行時執行;
8 X' @- h$ n4 A0 J5 N$ m: V, J8 A
! s) C% M& S' h- ]& ~9 \@DELI;
+ X, i! f C7 }$ |* F5 |
" o: X$ {! W6 F( a#類/命名空間的Debug調試#0 f1 S& C w( n. d6 Y
) G7 Y; e, K& x0 I
class ___X{. u1 \! c( H+ q
friend ostream& operator<<( ostream & _cout, const ___X & _a){
! s: `9 R/ f Z% y _cout<<"\n";
# v$ l7 P0 z. T( r. E' }; f& F DE_( "___X-Debug-Begin");4 e$ C! ?& v* j6 c8 w: v$ n2 t
: R; H) @1 T+ o, ?7 r
cout<< ?; // 此時不可以使用`DE_(?) 或 `Debug::__CoutItems(?)`, 必須使用原生的`cout`;
1 _2 W) B T B3 o- o) M& ~9 N) z H4 N& S9 ]0 |& g) G8 h! R* W0 t
DE_( "___X-Debug-End");' m, {5 W8 d( l! S3 @
}9 K, a, }& t7 ^' W; L" K
}
4 V* t/ k- A) ?3 {1 N6 u9 j. d6 {, @" z, [& S8 g3 z
namespace ___X{3 u, m& N% \4 Z
void Debug(){
8 _* h& q% |; W/ z DE_( "___X-Debug-Begin");- J& w, r9 C. X
+ Y/ `) c! A8 t7 M5 r
cout<< ?; // 此時不可以使用`DE_(?) 或 `Debug::__CoutItems(?)`, 必須使用原生的`cout`;
1 x' I- Q7 q9 w- p2 i0 j( }8 @# z7 x) n) }# j
DE_( "___X-Debug-End");$ e+ |# x- f, G% ]! h
}" {: F5 Y8 v6 u! J. W
}! o A6 M8 H" B; x! j# C$ y" v
9 x4 q' B1 l' T) ], W
@DELI;
$ i7 ^$ X- U7 {' @2 [: t1 s. n _8 s' U: [5 N
#嵌入模板的全局变量#
6 b2 C5 H4 \2 E+ K7 F2 l- E: F6 ^0 k6 f
{ // ___XX
L, r7 I! ^+ e$ F- H& ~ const int ___Number = ?; // 这里就叫做全局变量; 要以三个`___`开头
$ r [3 U; T6 x, o* D/ B. @ int ___N = ?;
, D5 T. S0 w4 } for( int i = 1; i <= 5; ++i){0 y9 k$ ?" t3 }% W
int a = ?; // 像`i,a`这种*临时变量* 可以不用写`___`开头;7 O! b+ m, K3 n7 i" s
}, r9 b6 H q1 P, t9 S
7 N. ]( ^/ k, x} // ___XX: H4 i+ ]( @$ ~/ x7 U
- C8 |# j1 e9 J E; u
@DELI;& G6 u5 }+ a5 ^9 N1 q* l t
; J4 R* D; D3 Y |. y2 B5 E0 R& E6 T
#Initialize函数, 强制的放到构造函数里#
1 \8 | N, J5 [3 ~最经典的例子是(建图)1 [4 T% C8 H4 x% x- g6 a! c
. P1 C @6 g) H: b
Graph( int _points_count_maximum, int _edges_count_maximum){}8 g- n! N' H5 ~
void Initialize( int _points_count){}* F Z- y# {3 @5 w; o
1' r, S( V* c/ j) Z6 y
23 L2 @3 W* `' s
这样分来 会导致, 每次使用时 必须是: Graph G( 100005, 200005); G.Initialize( n), 也就是两个代码行 (两个操作, 两个步骤)
p' N, m" ^( X6 N% [一旦忘记手动的调用Initialize函数, 虽然会报警, 那你还需要再去写代码 补上调用这个函数;3 u$ e8 v7 D1 f E
( b! ~/ ?8 d. t: I
当我们将Initialize函数, 嵌入到 构造函数 里
2 i e9 X4 R; l" E6 s* L
0 R3 z1 f5 h; \( ^. [6 h! L& p, LGraph( int _points_count_maximum, int _edges_count_maximum, int _points_count){
, T& X/ X& Q, b3 k; O8 F3 g ...
2 ^0 w2 b( X0 T: z0 Y //--( y8 ~: U5 @- c: Q
Initialize( _points_count);
" ?5 \" C" S }1 U- h}
: `! p, W, J; [9 Ovoid Initialize( int _points_count){}
3 D+ t, o4 w' F4 w" d9 A
3 O* I' |6 y( a/ V$ r注意, Initialize函数和原来是一样的, 只是做了两个事情:- E/ c$ p- O% w9 ?8 Q6 T& M& B
1 将Initialize函数的参数 接到构造函数参数的后面 (比如, 原来构造函数参数是a,b,c, Initialize函数参数是x,y,z, 那么现在变成构造函数参数变成了a,b,c, x,y,z): Z! s) e: ?; A. g
2 在构造函数的最最结尾, 调用Initialize( x, y, z)函数;* j" C0 e3 }" } c
/ Q: o' f1 v; V5 H1 _" a
@DELI;
; u6 A. R$ s& X' f
5 D/ s, K. T: _- I2 M#数组长度用函数传参来指定#- o7 [8 r* g6 _/ X, L2 ~ G
; B% M& v2 d0 b0 X: U/ R9 ~
template< int _Maximum>
- Z7 f9 j" y# d5 O `0 ~6 hclass ST{
% W, K3 V$ Y" n% c i ST(){* B9 x" T! a1 U- b5 \
array = new int[ _Maximum];
0 Y% f8 E( }$ M$ J }3 X0 G5 ~+ }7 A$ ^' D7 p# d
private:: c% X* k+ Q. F8 P% P& O
int * array;% @/ W/ y4 L/ \. T" G* t1 c
};0 `3 `! Y" E3 C; q% o( d( K
* A# R! w, C2 MThe above code should be replaced to:7 k( J4 v) ^0 }& I
! B3 d/ v& _/ i5 F) e& `. L1 @class ST{
2 I/ ^+ U/ ^" \! _* w ST( int _maximum)4 Z- p3 m S2 `5 M1 _
:% h" _! O/ q/ S% g
maximum( _maximum){3 a# ~1 K4 N/ J* T
array = new int[ maximum];& f/ j) r I1 Y8 \2 p
}
1 a D6 |2 ]! A2 Y$ Jprivate:
* B0 G' m% B# ]! J int * array;% f, B$ e' [2 ~. K
const int maximum;5 i1 J% Q- G. _/ U M# x7 L
};
! P/ h' n* C- N+ Y- N9 b4 Z
# X# t& B# {7 R1 u+ ~. w@DELI;$ y8 V, U2 i! W a5 H
笔记
' t" C3 m5 [) V b" r3 e有向无环图DAG
h$ I) e/ J; e" P, G. P最小路径点覆盖
2 F7 y" f* C d3 U9 u//{ @Snippet, `ZuiXiao LuJing DianFuGai (最小路径点覆盖)`. |: ?( O5 Z& q- X. y$ d/ h+ j
{
+ P: S# `) X& z& v7 b int n = `the points-range in the DAG`;# D' p; S" _( L
//--
* v$ F" j5 s$ b _ BipartiteGraph B( n * 2, `the edges-count in the DAG`);/ o) o1 p, [$ {5 P! @- ?5 h
B.Initialize( n * 2);3 S* n$ L; O8 W
for( int i = 0; i < n * 2; ++i){
% F4 n3 d/ R% x7 \ if( i < n) B.Set_pointBelongingness( i, true);
8 a, i1 V" B) F" G' u" ` else B.Set_pointBelongingness( i, false);1 i* b0 F7 t2 K8 T' x- _
}
: t- T L$ e' Z, D for( `s -> t` : all edges in the `DAG`){
; a6 r! f% |( j) q. i X8 u B.Add_edge( s, t, 0);: G3 W: Z! ]% @5 z
}
( M6 k; @& ^, L* f a //--
0 _% P4 W; v0 q( O# p3 j3 q& T7 S) X Bipartite_MaximalMatch M( &B);
4 C/ ]/ [& p, j, C5 u8 U% E, V8 G& M M.Initialize();0 S% c9 w6 i% X5 t6 c+ z% X ^: c
$(n - M.Get_maxMatch()) is the answer;; x( J' T" t1 [; ~& a, L
}+ f6 h6 k3 e$ n( j( P
//} @Snippet, `ZuiXiao LuJing DianFuGai (最小路径点覆盖)`0 Z; k; N6 d0 K1 r! ^* p
& O0 \5 ]# g8 y最小路径重复点覆盖, 最大路径独立集
& H8 \/ V8 S' E) B; G4 O7 |0 [//{ @Snippet, `ZuiXiao LuJing ChongFu DianFuGai (最小路径重复点覆盖)` `ZuiDa LuJing DuLiJi (最大路径独立集)`- j8 I( a A- I
{
6 G1 _* J8 Z; z& A- f int n = `the points-range in the DAG`;
g- {& p* t! r7 u; s bool * edges[ @PlaceHolder] = $(edges[a][b] means a edge `a->b` in the DAG`;% m, u7 i4 F+ j/ h$ C0 s" i
//--5 d* y* {1 l" O: }4 c9 O
$(perform the `Floyd-Boolean` on @Var(edges));
& ~- T- P2 c9 B, J( S //--
L! t0 `9 I6 ?, k BipartiteGraph B( n * 2, n * n);
# d, g9 |( a8 r+ y% B# L B.Initialize( n * 2);
$ @1 W$ p2 q g$ h1 O2 d9 i for( int i = 0; i < n * 2; ++i){/ y( k% E s: M& E: K
if( i < n) B.Set_pointBelongingness( i, true);
G6 w! X' g/ d. q2 S# \ else B.Set_pointBelongingness( i, false);' [; G5 R0 X8 Y9 E( h$ Z! C. c: i( t
}+ e, N. p9 J& b1 f$ z. D% u% k9 t
for( int a = 0; a < n; ++a){. R( x6 ~0 ~1 s2 c1 v
for( int b = 0; b < n; ++b){/ J8 y! |- X+ v
if( false == edges[ a][ b]){ continue;}
2 m6 y! `) h. L2 O B.Add_edge( a, b + n);
1 g$ G6 t1 A+ @7 D. w }! p' v- S5 E' Z1 ?
}9 O1 n3 y5 I, E/ p5 v2 l
//--
5 J" |& L! |, P3 B& `4 o) a Bipartite_MaximalMatch M( &B);- n5 \. Q+ y: S
M.Initialize();4 j* V! q: R* z5 [. m% m% \
$(n - M.Get_maxMatch()) is the answer;
/ c; U- P* _) ^+ k; V. ^}7 d$ o+ Y! `6 _# P
//} @Snippet, `ZuiXiao LuJing ChongFu DianFuGai (最小路径重复点覆盖)` `ZuiDa LuJing DuLiJi (最大路径独立集)`- w& W+ s% k7 P
3 `5 m G6 y* y! k% |6 yDAG的终点
U$ b1 Q8 y+ Q9 ~//{ @Snippet, `EndPoints of a DAG`: y5 Y" j$ r/ H5 _, @0 S4 b
{
- w: Q; w& a- i+ T" q; ^5 L int n = `the points-range of the DAG`;
B& I$ e& {4 i& O- t int * departure = `int ?[ >= n]`; //< the departure-degree of a point;* Q Y; J& F0 e1 b: s, `4 r) E
memset( departure, 0, sizeof( int) * n);& t4 I( Z% u; n, Z" c, B
for( `a -> b` : $(all edges in the DAG)){
, K* K* y+ U" W5 L; r$ P8 G: l ++ departure[ a];/ T- g( ?; T7 U# C- V( Q: v
}
* [4 y5 [" u5 u$ T) a1 P' ^ for( int i = 0; i < n; ++i){/ R" I2 V" s6 d
if( departure[ i] == 0){. |! G0 C4 {( ?
//< `i` is a End-Point in DAG
/ E; h6 n9 N& H/ Z$ F" ]" p }: g3 ]* L6 F# `5 y
}
& U; S. G8 ^# a% o}
1 a" j1 q# d4 T& ~5 z//} @Snippet, `EndPoints of a DAG`; Y/ _; R8 L. T1 E- x
1 b. A1 V) H/ [# _( NDAG的起点( \0 e+ @. O7 Y0 }3 w
//{ @Snippet, `StartPoints of a DAG`
; Q' O: w* H0 r$ ~' U. }{
" Z0 o0 ^# X9 [1 B3 c! h1 R int n = `the points-range of the DAG`;$ h; S# z6 {* k' I8 T) E3 J1 y
int * incidence = `int ?[ >= n]`; //< the incidence-degree of a point;, Y5 g2 h6 F2 O3 C5 i' L" ~. t2 [- |9 V
memset( incidence, 0, sizeof( int) * n);6 I/ v H1 q* V3 E8 @* p7 k9 Z
for( `a -> b` : $(all edges in the DAG)){
, G) D0 b$ K/ J4 B+ s1 c ++ incidence[ b];% }* Q( m2 L- X( b1 N% }7 m
}8 f3 e" }- d4 j+ J( H# m0 ?
for( int i = 0; i < n; ++i){
a/ ~* C; I- z; E7 W# B0 D if( incidence[ i] == 0){0 o) M" p8 x- `. ? I
//< `i` is a Start-Point in DAG
# }: S7 b& M" D9 C* l) A9 X) P }6 H1 X* b8 Q# d5 N) N
}
; |/ _9 J; U& s* y}
% S& q7 e- W$ u- S' N) e//} @Snippet, `StartPoints of a DAG`% M& r+ t0 X; [) ]4 x1 ~7 P9 m
; Z0 E8 |$ ^( ]
判断一个图是否为DAG, 求拓扑序2 J/ a$ H9 ]! }9 L
bool Work(){, a, Z# q, G& N8 p9 c0 s) s m1 _
//< `1` Check whether a Graph is a DAG; `2` Get TopologySequence;1 x) `: K6 _, O* J4 y. r; @5 ?
int points_range = @Unfinished;6 j5 Z( `# ~; O7 H1 O2 Q
int * topological_sequence = @Unfinished(an outside array whose length must `>=` @Var(points_range));
6 f& [( e! y" Y- L" g6 ?9 t int * incidence = @Unfinished(an outside array whose length must `>=` @Var(points_range));$ C* w% s' V' u i/ G e
memset( incidence, 0, sizeof( int) * points_range);
! n; @/ Z5 @) Q( _0 |/ P" G for( `a -> b` : $(all edges in the DAG){
7 k1 X& f% ?% O ++ incidence[ b];. k, p' a& O S
}
- t% ?" m* u9 Z/ S9 u int size = 0;, m, e, L$ b! H2 p3 i. |7 a
for( int s = 0; s < points_range; ++s){
( X9 r$ Z+ u6 Y; n' P( M if( incidence[ s] == 0){
* c( I+ e: `, B2 S! n' A topological_sequence[ size] = s;& K5 K- u% M' T+ D% F
++ size;" @3 |2 ^; _4 _. v7 v6 ?% s( x+ \
}
; _2 n, R" I* X+ X0 O }2 d- U# Z0 e7 S* H' f& t
int head = 0;% T2 `: S# D4 I& F! }
while( head < size){0 F2 B4 X. } W" e
int cur = topological_sequence[ head];
" Y- J5 `4 i% X( T0 N ++ head;
* X: U9 v; ^' q) w: B3 O' W% n8 p- K for( `a` : $(all adjacent-points of `cur`){+ ?. Y. p4 h7 b
-- incidence[ a];
' C: s8 w3 Y, e, b: {. f9 _ if( incidence[ a] == 0){
& A; }/ l5 E9 z6 ` topological_sequence[ size ++] = a;
: p0 M# F- u5 w" g, T; T. h- p }. H6 `9 c; X/ X. W/ ?
}
5 ~- D% G2 z, r. u/ ]( M5 d- { }0 {5 x5 e0 N; Z* M
if( size != points_range){
( S8 x, ~5 b+ T, L& y- a return false;! S! p7 Z* v# T$ u) v
}1 U7 o- v9 p( |3 a% b/ r
//>< The answer Topological-Sequence has been stored in @Var(topological_sequence)2 X# ^% {% v$ n& `) Z
return true;0 R* h2 e7 h! X# p
}* _/ X2 F' F* r6 F [
3 l7 R7 W9 ]+ V! \
图论& N, c& Z! x# o' ^ ]/ H' c" G8 R
最短路
8 G9 c3 @! D$ R- QTARJAN$ G! U- F" ^$ J# @' e0 L
无向图-PBCC点双连通分量
1 [9 Y1 C% k- x% c# N: h0 c+ 割点- [% a% t! H4 w! O- x; d
3 i" l, E0 A# y5 X" e, K
//{ Tarjan_PBCC-Declaration# R9 f! _' C7 }' i3 r
template< class _Edge_Type>
9 P# x$ }+ d. }7 g/ q4 eclass Tarjan_PBCC{4 ]2 f( M0 ?9 H% V0 i+ X- o( c
public:
8 ^ G( v0 |5 Q const vector< int> * Pbcc;# S* H3 |( S7 C; q: p# k( E+ b
const bool * Is_cutPoint;7 A2 @+ {( w* r4 f' W
//-- variable ends# V# ~1 O0 e4 ~" l' q
Tarjan_PBCC( const Graph< _Edge_Type> *);
& W9 a8 R+ i2 t, ~( P e4 I5 |9 K void Initialize();7 _2 L+ Y5 Z5 ]: p3 I5 E- e" E, l
int Get_pbcc_count() const;
) I3 F9 Y' H7 j' ]! yprivate:8 L) V5 y# I1 D" ?- h
const Graph< _Edge_Type> * graph;4 G z8 z$ p* a; B
int * stack_;# w! z5 o! _3 q, L% }3 {$ r$ V X
int stack_top;
0 s/ k7 n4 \. f2 Q% r int * dfs_id;
: W' ]' ~" g3 E+ Z: @ int dfs_idCounter;
: S$ s2 F( ?; H N' @ int * low_id;5 Z* H" j7 E- Z
vector< int> * pbcc;: G' j4 L; w/ h t6 e+ u
int pbcc_count;7 h( `/ B0 u/ ?
int dfs_startPoint;
2 A- U% Z0 m" r* c bool * is_cutPoint;
. j$ D* U3 N2 r2 D int cutPoint_count;
) r3 c, s: ~3 r0 B //-- variable ends& G8 Y" s# {' B6 a2 l) s
void dfs( int);2 k5 U4 U! l6 S# {
};% X+ d8 n" w0 }+ g& X5 N
//} Tarjan_PBCC-Declaration
8 c1 N. u# [5 F+ \- N0 ~
0 N, v' j. P) Y4 T, g//{ Tarjan_PBCC-Implementation) u7 V2 G. i3 ^6 R: i, M5 S5 u
//{ Variable-Annotation
, M* }. c" o1 o5 I //{ @Var(pbcc)
- t* l& X9 t( v- d# `8 p // + `pbcc[i]={a1,a2,...}` means that the PBCC with id `i` consists of these points {a1,a2,...}* K, q9 F* j' y2 x7 n' G
//} @Var(pbcc)9 g" j: n# ]9 I
//{ @Var(graph)
, { `' T1 E$ K) V* K // + must be a undirected-graph, i.e., Edge[i] = Edge[i^1]
3 O E: [: M# ]1 ~4 t6 N7 M //} @Var(graph)
( O8 z& E6 K9 K0 N, P7 W //} Variable-Annotation9 V- H" q3 [! o& V1 J5 T
template< class _Edge_Type> int Tarjan_PBCC< _Edge_Type>::Get_cutPoint_count() const{ return cutPoint_count;}
, j. C, L y6 Ttemplate< class _Edge_Type> int Tarjan_PBCC< _Edge_Type>::Get_pbcc_count() const{ return pbcc_count;}
& {2 C+ q4 B& X8 M- w* V# z1 Q; jtemplate< class _Edge_Type> Tarjan_PBCC< _Edge_Type>::Tarjan_PBCC( const Graph< _Edge_Type> * _graph)+ F$ f# k9 k, T! @, F# w% {5 I, d
:
2 N- X& B( v$ @2 o6 [$ E$ | graph( _graph){# b. ^& U6 {% s) d9 N
stack_ = new int[ graph->Get_pointsCountMaximum()];& i( ?; m+ Y' o+ v: c
dfs_id = new int[ graph->Get_pointsCountMaximum()];
y. g9 a) B' l0 C6 G; q* [ low_id = new int[ graph->Get_pointsCountMaximum()];
/ U. i" L& _9 s8 y+ B. c5 y pbcc = new vector< int>[ graph->Get_pointsCountMaximum()];7 |7 }) l4 O2 A
is_cutPoint = new bool[ graph->Get_pointsCountMaximum()]; q; t& u9 @ I! a0 C4 j
//--
3 r! v2 q: [; L: y) c, X a5 r8 S6 p Pbcc = pbcc;5 L6 H0 `) \2 O
Is_cutPoint = is_cutPoint;
, D4 k: K' i2 W/ ? d+ I) d}
' ^, b+ O. a y% c6 Z8 u3 ctemplate< class _Edge_Type> void Tarjan_PBCC< _Edge_Type>::Initialize(){; d+ K. \4 \) U- N) I
stack_top = 0;. ]7 n/ e/ G. P, C# Q
dfs_idCounter = 0;1 l5 t0 m* a7 e1 y. a0 p
pbcc_count = 0;
1 T7 d( u8 k- O4 H( \9 A6 ^8 M* j4 B cutPoint_count = 0;
- q( b( _# M j+ R2 S- z) h4 U0 V for( int i = 0; i < graph->Get_pointsCount(); ++i){ pbcc[ i].clear();}
/ Z' Y4 P9 O- P" k. }) l" V0 ] memset( is_cutPoint, false, sizeof( bool) * graph->Get_pointsCount());) |/ o, T. Y6 Q0 d. @: W
memset( dfs_id, -1, sizeof( int) * graph->Get_pointsCount());) |0 E2 i7 D7 e( j" {
for( int i = 0; i < graph->Get_pointsCount(); ++i){
- t' I. z/ y6 q if( -1 == dfs_id[ i]){
" Q" \8 N" A J2 R9 v& \. G dfs_startPoint = i;: T3 } G, r% ]- G: q; t& G
dfs( i);! D' v0 d: ^. @# J* {- e
}7 v7 J+ q1 N5 Z8 N r* t: \
}% A1 z8 D2 |$ J* c
}! v _9 N+ m' K
template< class _Edge_Type> void Tarjan_PBCC< _Edge_Type>::dfs( int _cur){
! l8 d% t! Y4 \% f stack_[ stack_top ++] = _cur;
! J7 e' ?, j; m$ p" O) s; ~ low_id[ _cur] = dfs_id[ _cur] = dfs_idCounter ++;+ I, d3 G& P$ ?" d
//--5 b j4 \- A: U, J2 C5 @
int cc_count = 0;
8 M7 T, r( `, ? if( _cur != dfs_startPoint){ ++ cc_count;}8 R' S9 h1 r2 O8 P7 z
for( int nex, edge = graph->Head[ _cur]; ~edge; edge = graph->Next[ edge]){5 c/ `& F7 V7 |1 }
nex = graph->Vertex[ edge];
- p! `, y8 s$ S T- A" b- | if( -1 == dfs_id[ nex]){
1 I( x5 ?3 d: ~( f1 ^ dfs( nex);
# J( S7 Q4 H6 |3 _1 J7 G0 ] //>< `low_id[nex]` always `<= dfs_id[_cur]`
: R# r9 |6 ?4 @/ @ if( low_id[ nex] == dfs_id[ _cur]){% r" c9 a+ H6 m
++ cc_count;4 V5 _$ k& t" b
if( cc_count >= 2){9 i: ?- }1 \+ k
is_cutPoint[ _cur] = true;8 M' o" t4 A/ } Q
++ cutPoint_count;
. V$ ]# [! y" b, D% Q5 [6 C while( true){
" K1 Y! ^3 B5 z$ A$ y+ T% } int c = stack_[ stack_top - 1];/ F9 W. b& j0 G2 G+ }4 o
-- stack_top;
) k, V, k4 x9 R 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.) C/ r( K' U' J
if( c == nex){ break;}+ b: n8 `+ W2 Q- w8 v5 k
}: u$ {; I) b3 Q' f8 t4 S5 B
pbcc[ pbcc_count].push_back( _cur);: {& Q, f- C# s. V! U8 ]9 l
//>< `pbcc[ pbcc_count].size()` >= 2
" p# w0 [% R- j) J& o ++ pbcc_count;* a+ J# g2 @, l: G
}: S3 H3 v1 `- R5 W" i
}$ ^' t, {' _2 @! I7 u$ e
low_id[ _cur] = min( low_id[ nex], low_id[ _cur]);
& L* x! a4 ~" C }0 O5 V! o3 k3 t9 ]1 O0 b! `( }
else{ //< `nex` must on the `stack` due to the graph is Undirected
6 B6 a/ X9 Y4 N# O; A( g f low_id[ _cur] = min( dfs_id[ nex], low_id[ _cur]);
: F) o8 O9 r7 u7 K }
7 D# d- ? o6 c. h. Q }
( H/ V v9 f" j/ X5 ?( r //--
# f% J' d" y1 t" H) X6 @ x if( _cur == dfs_startPoint){8 T: R6 S1 b$ ^" C5 l1 w
while( true){- z9 X6 P- z5 T8 Z; `
int c = stack_[ stack_top - 1];
% c" [3 ~- Z" _% V$ w -- stack_top;; Y8 D. z$ ]/ |3 ~5 m
pbcc[ pbcc_count].push_back( c);
N; ^8 l2 [2 }, X+ r if( c == _cur){ break;}3 O: N) H& J' w F
}
* d' j c+ z7 W ++ pbcc_count;1 j- o1 g) k+ X% S4 A0 i- W* U
}. _4 r' X6 Y G7 b3 b* M
//>< `cc_count` means the number of Connected-Component when `_cur` was removed from the current Connected-Component (whatever `cur` is Cut-Point or not);
& }# }: q% {' X2 w}
4 g3 a$ ]+ a- Y//} Tarjan_PBCC-Implementation
: S: n0 G% K, c @4 b; X ]
0 v3 r0 Z# J1 `+ L8 z* e* g; [$ k F! E无向图-EBCC边双连通分量: {1 h6 z" l0 I" H
+ 桥: W) B+ E$ k( N4 ]: T" A$ y
+ p0 B' \# P! s3 ~9 O$ [+ w. C//{ Tarjan_EBCC-Declaration
9 x; {3 V+ v2 `4 I/ q N, D, d4 Itemplate< class _Edge_Type>
8 ?; r) _" K0 j& \class Tarjan_EBCC{% c6 p0 V; I D I
public:8 i# I* q9 Q4 T' p
const int * Ebcc_id;
. G9 l% J9 @1 b% @# k; j# Q const int * Ebcc_size;% E7 F' T- Q' X, s& ]& y
//-- variable ends) r5 X) D3 p4 [. L3 Z& |& O6 r& \
Tarjan_EBCC( const Graph< _Edge_Type> *);
z$ t" R8 X9 c void Initialize();/ }2 X3 F z. ?, ~
int Get_ebcc_count() const;: Z1 [' I X6 s4 N$ N0 f q
const Graph< _Edge_Type> * Build_tree() const;' O# a* l% |: c- B
private:
9 ]- ]7 V6 i% i! ]9 a0 d const Graph< _Edge_Type> * graph;9 @7 i8 v# H5 |+ F% F& T. X9 W9 W
int * stack_;
# b$ Q* s! [+ S int stack_top;1 t3 e/ f7 r5 _0 w4 I$ H2 B& j
int * dfs_id;9 Q7 N, H5 v! I2 {+ f- M% X7 t+ g! s
int * low_id;
, {: w' ~3 S- q0 K+ g" l int dfs_idCounter;
- ], M8 s7 ]9 J Y3 |$ W int * ebcc_id;, y& d' C; s0 G- N
int * ebcc_size;+ i: b# D+ e4 r: [$ T1 v. Q
int ebcc_count;
( |+ u6 D# y$ ]1 m) X/ E //-- variable ends
|* l! k" g& w. K( J7 z3 v9 ~. z void dfs( int, int);6 r4 {9 E3 M3 r& I5 {: g$ ~
};7 B& Z+ H# Y0 L: _ h2 o7 S
//} Tarjan_EBCC-Declaration
6 S1 D" I7 w" M, x9 B9 I6 ^/ u) u
//{ Tarjan_EBCC-Implementation
. s1 H9 P. s h. j //{ Variable-Annotation0 P: Q- k1 B7 F1 i3 H X
//{ @Var(graph)5 [2 [" O1 [9 w) b5 Z+ m
// + must be a undirected-graph, i.e., Edge[i] = Edge[i^1] H+ t1 L! a! {% v% ]
//} @Var(graph)
. V5 `3 J t1 o2 X) m9 @8 F/ { //{ @Var(Ebcc_id), Z: E4 D3 f% a% F
// + `y=Ebcc_id[x]` where `x` is a point of @Var(ptrRef_graph) and `y` belongs to `[0, @Func(Get_ebcc_count)-1]`2 r/ P [; r1 k, q2 u/ J2 h
//} @Var(Ebcc_id)
+ f. P. e" T+ b% u //{ @Var(Ebcc_size)
8 f( ? H5 ]& j) u0 j // + `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)
% H* O1 x" t% V! A; m( b" G //} @Var(Ebcc_size)$ o/ R8 U# ]+ r
//} Variable-Annotation+ }& H+ ]3 l$ b# }
template< class _Edge_Type> Tarjan_EBCC< _Edge_Type>::Tarjan_EBCC( const Graph< _Edge_Type> * _graph)
5 x# }" ?9 q( ?( H :
0 Z( x2 `5 m: D E& h graph( _graph){! e- l7 Z8 s# A: S6 ?
stack_ = new int[ graph->Get_pointsCountMaximum()];
% m% G, P% l5 {" u( C" R% l! y ebcc_id = new int[ graph->Get_pointsCountMaximum()];
/ ] L& G0 N8 a% I! ?. J ebcc_size = new int[ graph->Get_pointsCountMaximum()];
* s8 ?# `6 l$ Z; g n/ _ dfs_id = new int[ graph->Get_pointsCountMaximum()];! R. I, P* }( n) ^' K6 Q6 b% F' R6 F
low_id = new int[ graph->Get_pointsCountMaximum()];- S- n# l6 [9 `% x# C3 C
//--3 D9 l V( n5 n5 ]- b
Ebcc_id = ebcc_id;7 Y q E) K/ {; L$ W8 o
Ebcc_size = ebcc_size;
8 g0 @* z/ o+ L' @* r! J& y$ j}
2 z# |6 w7 e5 M# N# Otemplate< class _Edge_Type> void Tarjan_EBCC< _Edge_Type>::Initialize(){
' {5 _; [7 u E stack_top = 0;: @, b, Q6 C$ E5 J
dfs_idCounter= 0;
+ `# a V$ F$ C; G0 d2 q- e ebcc_count = 0;' o; r4 W" r6 j' H( ^
memset( dfs_id, -1, sizeof( int) * graph->Get_pointsCount());
* P: {9 f8 g1 [% o/ I4 S# { for( int i = 0; i < graph->Get_pointsCount(); ++i){. D9 [* ]3 C/ @: p
if( -1 == dfs_id[ i]){
# n9 M* A( l" P: h( o dfs( i, -1); [ K/ Y- Q+ o
}) {* Y$ a, E( ?% Y* W A1 l
}# K4 K: n/ z3 q: b1 H7 m* g% L# K
}
4 J, z( f. w6 r% mtemplate< class _Edge_Type> const Graph< _Edge_Type> * Tarjan_EBCC< _Edge_Type>::Build_tree() const{/ b. d* A M3 M* \8 l
//< + Make sure @Func(Initialize) has been called- m' B i! Y7 [, M/ N
//< + There is at most one undirected-edge between any two points in the Tree (i.e., @Ret), d0 z, L) c: ^' j$ p( M. E
Graph< _Edge_Type> * Tree = new Graph< _Edge_Type>( ebcc_count, graph->Get_edgesCountMaximum());' I0 D; l' b( N! w: v3 o% W
Tree->Initialize( ebcc_count);/ `: ~; m: E- _
for( int a, b, i = 0; i < graph->Get_pointsCount(); ++i){
* U9 Q+ X5 i' h2 I3 C! p for( int j, z = graph->Head[ i]; ~z; z = graph->Next[ z]){
+ y& W* b/ h: T7 C j = graph->Vertex[ z];
a# }3 w' z6 s1 j a = ebcc_id[ i];
, o' G& w& U2 C% g b = ebcc_id[ j];3 ^+ w3 S h& i
if( a != b){+ ]/ m2 E ?4 \# H$ X0 M
// Now, there must has no edges between `ebcc_id[ i]` and `ebcc_id[ j]`! U: O9 J8 g+ r6 ~! V- y
Tree->Add_edge( ebcc_id[ i], ebcc_id[ j], graph->Weight[ z]);* j; F4 T: ^! C E' ?6 c
}: i* \0 G9 Y& c% c" y
}
: x' `' G. R; j) H }: [; g! m# K: E. B1 ~* h
return Tree;1 G& Q6 m- p0 j2 Y$ L5 L
}) B& N( d, ^. _! z- ^
template< class _Edge_Type> void Tarjan_EBCC< _Edge_Type>::dfs( int _cur, int _father_edgeId){
' o( ]8 n9 L4 b7 M stack_[ stack_top ++] = _cur;7 i$ V6 I- H3 l
low_id[ _cur] = dfs_id[ _cur] = dfs_idCounter ++;1 B3 w, @% |$ k4 m
//--* q6 f* d) p9 {5 p
for( int nex, edge = graph->Head[ _cur]; ~edge; edge = graph->Next[ edge]){6 V4 \, L" ~! ^
nex = graph->Vertex[ edge];5 @1 e( j6 ]9 J6 A$ {4 e
if( (edge ^ 1) == _father_edgeId){ continue;}* d x8 b5 M4 j5 |$ y
if( -1 == dfs_id[ nex]){
/ s6 a( s) Y4 B4 W! l dfs( nex, edge);
9 u5 f; R* e2 t8 { low_id[ _cur] = min( low_id[ nex], low_id[ _cur]);2 x" \& \7 G! t0 M- H& a
}
( `* A8 Z, s( [2 R8 l7 r. ^3 W2 p: e else{3 M% l0 H7 |0 s8 C, H
low_id[ _cur] = min( dfs_id[ nex], low_id[ _cur]);
1 m1 z, O. c, b% Q/ Q }
a' [ @, l& e, ]) o }3 T% _1 r2 N8 F- G; W! \
if( low_id[ _cur] == dfs_id[ _cur]){
" M) ^( A2 n. @; N7 s ebcc_size[ ebcc_count] = 0;6 n3 j* i- W& l+ a+ F$ N9 J
while( true){9 O6 P5 _: O4 [1 [) c M
int c = stack_[ stack_top - 1];; h. _! H% [* b [2 M. l
-- stack_top;/ l- O( @8 u- ?5 s2 u& B1 F7 ~
ebcc_id[ c] = ebcc_count;
* }6 u8 [$ v# F8 r# T I; k ++ ebcc_size[ ebcc_count];1 Q6 V) o1 S& g" b) e3 ]
if( c == _cur){ break;}% Y8 E# ~& W3 w, l* p
}
$ N& T/ d6 i- L9 n2 r7 [ ++ ebcc_count;
- T& T/ c6 N' Y, y" A2 e0 R4 k3 | }# w5 n5 K V; i9 ~6 D
}
% b' H/ ]1 d) V//} Tarjan_EBCC-Implementation
0 \3 m3 Y" k; R0 b& U! _3 g5 }7 S6 Q5 p
SCC有向图强联通分量4 U- P' h0 l: M2 q- H1 V O" E
//{ Tarjan_SCC
! L! X9 n" Q, C" B& Qtemplate< class _Weight_Type># N) t& R X3 U7 z
class Tarjan_SCC{
- [- z1 x: y) ?6 o& D2 \) s5 Xpublic:" e) V0 q* j- Y. \; F H d
const int * Scc_id;
+ U" K- D! K6 r! i; A const int * Scc_size;; W" X/ I$ Z `0 K, g
//-- variable ends
/ V- o- O9 ?0 F" M) { Tarjan_SCC( const Graph< _Weight_Type> *);
' S( s" Y$ d0 a1 }0 w! N void Initialize();- P& j8 h L+ v
int Get_scc_count() const;' a! G% G7 g4 E4 e( W+ S
const Graph< _Weight_Type> * Build_DAG() const;$ t/ r% g, A& G/ U" m: M5 Y
const Graph< _Weight_Type> * Build_DAG_uniqueEdges() const;- y+ v' F' I, s
private:$ }1 A8 q5 p" {: [8 A
const Graph< _Weight_Type> * ptrRef_graph;2 f: f4 ]' m( j6 ~0 ^* V! _
int * ptrNew_queue;3 g% X' k6 G& |4 p; @
int queue_tail;
7 ?- o' K2 O1 S( @2 z7 _$ }; Z bool * ptrNew_isInQueue;) j. W8 E& r& o8 w0 m8 h
int dfsOrderId_counter;, r; T% {: A' L* @& C& R! O
int * ptrNew_sccId;; h7 O; c/ }1 b7 \7 O0 h9 s
int scc_id_counter;1 \8 C+ z0 d; N' z
int * ptrNew_sccSize;
. ]! t9 U( q/ ~0 x( f! [ //-- variable ends+ Z. S5 P; `3 m
void dfs( int); S( G* e1 }% a" L
};- d' z/ o9 M% f" ?1 c
//{ Variable-Annotation
4 w5 P& ~5 Q: b, F7 u// + @Var(Scc_id)# H6 m5 r3 p7 n) Q$ V
// . `y=Scc_id[x]` where `x` is a point of @Var(ptrRef_graph) and `y` belongs to `[0, @Func(Get_scc_count)-1]`. |3 X; s; F. x1 P' D
// + @Var(Scc_size)+ u. |7 E Y: I
// . `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)
0 k: x" o# [6 [( b- \2 U//} Variable-Annotation* Z0 \5 O' m5 ?8 o: G4 ~
template< class _Weight_Type> Tarjan_SCC< _Weight_Type>::Tarjan_SCC( const Graph< _Weight_Type> * _graph)" w, P$ @+ ^( y( ]0 Q
:
% v% @ E; q5 U8 t ptrRef_graph( _graph){
2 w5 h, o6 f. Q( c3 m7 ], N ptrNew_queue = new int[ ptrRef_graph->Get_pointsCountMaximum()];
4 z( I1 c) u$ ~; \4 z ptrNew_isInQueue = new bool[ ptrRef_graph->Get_pointsCountMaximum()];" ?; I0 [& M% j3 i7 }9 f! y+ B( f
ptrNew_sccId = new int[ ptrRef_graph->Get_pointsCountMaximum()];' E9 ?1 B0 c1 |( Y8 b4 i
ptrNew_sccSize = new int[ ptrRef_graph->Get_pointsCountMaximum()];
) l6 A1 m+ ]8 J& Q( _: V1 K7 O //--* `: F6 X8 _9 v4 w5 Q+ E( ^
Scc_id = ptrNew_sccId;
$ p- J& J) v$ B. P; V% K8 r1 q Scc_size = ptrNew_sccSize;
" |: C- P) X; `# l- }* h}/ M* \/ L$ N, K, Z$ C1 U
template< class _Weight_Type> void Tarjan_SCC< _Weight_Type>::Initialize(){
6 n+ e+ {, Y' Q$ W" P queue_tail = 0;. z2 f# f- {0 T
dfsOrderId_counter = 0;
/ C" w2 g0 H& V: g memset( ptrNew_sccId, -1, sizeof( int) * ptrRef_graph->Get_pointsCount());! |' P/ B: Z5 C4 g3 `
scc_id_counter = 0;
* Q4 M7 f+ k7 W for( int i = 0; i < ptrRef_graph->Get_pointsCount(); ++i){
7 l; a: E0 |, Y4 |: S7 {) i2 q% J if( -1 == ptrNew_sccId[ i]){
9 @' l$ m( Q$ N5 k. [ dfs( i);
8 m5 u: H. }& I }- }1 x* H" A; M% ^6 h2 c5 \& N+ \' Q) f
}
" \& Y) P$ ^+ {' _) u% q}
. F9 C. S! z% Ntemplate< class _Weight_Type> const Graph< _Weight_Type> * Tarjan_SCC< _Weight_Type>::Build_DAG() const{4 h' C- ` B0 t9 [- J7 K3 g
//< + Make sure @Func(Initialize) has been called
+ u3 B9 `. N( Z7 c7 _7 [' k" w Graph< _Weight_Type> * DAG = new Graph< _Weight_Type>( scc_id_counter, ptrRef_graph->Get_edgesCountMaximum());
0 M) @" r, Y/ |! }: \ DAG->Initialize( scc_id_counter);+ E) U* V7 v' f2 W& r
for( int a, b, i = 0; i < ptrRef_graph->Get_pointsCount(); ++i){
; B1 M, ^+ L( R9 L! D for( int j, z = ptrRef_graph->Head[ i]; ~z; z = ptrRef_graph->Next[ z]){
3 a% s: f6 |4 r3 N j = ptrRef_graph->Vertex[ z];; i! h0 D) P8 }% R& T* F- C, l
a = ptrNew_sccId[ i];
4 O/ o3 d. U6 T b = ptrNew_sccId[ j];6 j) Y9 x8 b* J! t7 e/ ^' h2 S
if( a != b){" c7 y/ R0 @- J+ d/ u
DAG->Add_edge( ptrNew_sccId[ i], ptrNew_sccId[ j], ptrRef_graph->Weight[ z]);/ ~, X. N3 ~6 n. K
}
3 Z# c B( Y! ]# O' [) h }
; y7 h5 z8 z2 w3 ~. [ }6 K8 u$ j% F8 I/ r1 T" O
return DAG;8 p( I) ^) Z+ T$ j9 k
}+ Y: x# h9 ~$ A+ y. r7 I+ _
template< class _Weight_Type> const Graph< _Weight_Type> * Tarjan_SCC< _Weight_Type>::Build_DAG_uniqueEdges() const{1 u/ Q* P& k! h
//< + Make sure @Func(Initialize) has been called
$ I! F9 n/ [9 F7 J( D7 d//< + There is at most one edge between any two points in the DAG (i.e., @Ret)" n9 a. Q" Y/ u6 O* \1 @
unordered_set< long long> hash_edges;
) P4 c5 T x& t/ U+ I- A' F Graph< _Weight_Type> * DAG = new Graph< _Weight_Type>( scc_id_counter, ptrRef_graph->Get_edgesCountMaximum());% D. i, v# I: y; Y$ t K$ C, ^" e( L+ V
DAG->Initialize( scc_id_counter);
7 P- l9 b4 s u7 c1 { ^/ W' }4 ] for( int a, b, i = 0; i < ptrRef_graph->Get_pointsCount(); ++i){) A1 B" o5 ?, w+ i$ j0 F
for( int j, z = ptrRef_graph->Head[ i]; ~z; z = ptrRef_graph->Next[ z]){
, J9 K) [# ^% e% F0 s( @6 ? j = ptrRef_graph->Vertex[ z];* |+ ~" @- ^* s
a = ptrNew_sccId[ i];) w7 L1 e) s% K9 ~8 D _
b = ptrNew_sccId[ j];/ | o2 t: H9 c; y3 R" O* ~% W
if( a != b){. F @. s) v( I8 C$ {
long long hash_val = (long long)a * scc_id_counter + b;
g& N8 X, W0 y if( hash_edges.find( hash_val) != hash_edges.end()){6 m. Y# Q* r) d# q! L2 [2 J6 C
continue;
# ^, K" A, K7 Q- y3 i }
' S( e+ U) \9 W. O& w- _$ ` hash_edges.insert( hash_val);4 y2 F/ c3 o' I0 ]0 {
DAG->Add_edge( ptrNew_sccId[ i], ptrNew_sccId[ j], ptrRef_graph->Weight[ z]);
) c# n2 H, w% E, h8 c: t }
% o& ^* c( F8 Q5 I/ N4 ^ }; w+ z0 u2 O( Y. {. O& ^* v
}
% s/ y' ~2 K9 { return DAG;& Q# H9 N- i2 I( _& N3 `- E8 l
}+ p" [/ U! s5 G+ S* V( {. j
template< class _Weight_Type> void Tarjan_SCC< _Weight_Type>::dfs( int _cur){9 h5 G: w7 h' ]) C N. ]1 m
ptrNew_queue[ queue_tail ++] = _cur;- x" ?: ^% ?4 f3 f9 y! e+ o1 B
ptrNew_isInQueue[ _cur] = true;
4 }# n+ j0 E+ L int current_dfsOrderId = dfsOrderId_counter;
* M, i; K" Q+ ?, h ptrNew_sccId[ _cur] = dfsOrderId_counter ++;
: F3 W/ L k% e% k: {7 z" O9 l //--+ D8 i; Q6 J$ n9 I) e' D
for( int nex, i = ptrRef_graph->Head[ _cur]; ~i; i = ptrRef_graph->Next[ i]){
' y, O% g% |( d0 _% b7 g nex = ptrRef_graph->Vertex[ i];
5 p* x7 W8 R6 x% Z if( -1 == ptrNew_sccId[ nex]){
& w+ ]- C' g, H dfs( nex);; l1 U \& k" S. v& l( f
}
8 J+ n" R( c- S; |8 g if( ptrNew_isInQueue[ nex]){8 |- Z# E4 P7 D
ptrNew_sccId[ _cur] = min( ptrNew_sccId[ nex], ptrNew_sccId[ _cur]);
+ j$ U7 x) D! ]- M }" e. Z3 k9 K5 \5 ]
}
( ?: s; t- Z& U, e5 n if( ptrNew_sccId[ _cur] == current_dfsOrderId){; x. m8 G/ R3 M0 I6 A1 o; E; p8 A
ptrNew_sccSize[ scc_id_counter] = 0;
# w- O4 `5 F2 x! j; z while( true){4 a2 }* k' N0 w$ ?; |
int c = ptrNew_queue[ queue_tail - 1];
) @7 B8 ]2 J9 m9 { ptrNew_isInQueue[ c] = false;: \# i+ b* y& v" v& g
-- queue_tail;4 G. Y1 r/ P4 t# P
ptrNew_sccId[ c] = scc_id_counter;" P2 M4 r( P1 T( j4 X
++ ptrNew_sccSize[ scc_id_counter];: u% n2 R# Y9 ^& G6 N0 M8 k
if( c == _cur){ break;}
' p: j7 ~/ \5 O }+ F7 u( o% ?' V: D6 j% W
++ scc_id_counter;
_1 F' G! D( u }
% u; W8 |( P2 _}
3 y! v/ ^( z* H, B2 i: g//} Tarjan_SCC
1 H% W# D7 i: ?, Y" e5 B! u* W8 U* p+ `% s0 V
差分约束系统,不等式组
8 }8 i7 {2 ^! A. @) F//{ Minimize_InequalitiesSystem
/ S+ n% B4 Z9 J8 p; g/ Ktemplate < typename _Edge_Type, typename _Distance_Type>
3 W5 M1 b# s# p4 ?5 K# F: nclass Minimize_InequalitiesSystem{0 k! P; u! I+ \& X
public:0 M+ V+ o- e$ |7 V; O# a% [ U
const _Distance_Type * Distance;
8 R0 I2 e8 X' S //-- variable ends
- V' _1 [* x& F: s' f Minimize_InequalitiesSystem( const Graph_Weighted< _Edge_Type> * _graph)
! g7 L' ^5 J2 C# |! B% }- y :
# O6 \ |0 R5 n ptrRef_graph( _graph){
5 A1 {( e& [# ?6 C( z6 ~( Q" j0 x ptr_distance = new _Distance_Type[ ptrRef_graph->Get_pointsCountMaximum()];9 X0 q9 N5 }: \( k
Distance = ptr_distance;
- `2 {8 V3 X& [2 E, {* q ptr_isInQueue = new bool[ ptrRef_graph->Get_pointsCountMaximum()];
/ I2 W4 \7 K# @ ptr_queue = new int[ ptrRef_graph->Get_pointsCountMaximum() + 1];2 t( N( K( I8 C+ R
points_range = 0;
" }, U' H W0 k( S% @" t' U8 I ptrNew_pathLength = new int[ ptrRef_graph->Get_pointsCountMaximum()];5 v" C( y; Y$ i* a4 \5 W
//--
7 z5 u. c7 n9 U2 c# F& {4 d7 { Initialize();
+ C8 e1 k$ D# W }
! R# ~# T% v) `4 b* i0 Y1 U& G void Initialize(){* S e" V8 v/ I! a
points_range = ptrRef_graph->Get_pointsCount();
4 D& @0 a; g/ h5 s3 T }7 g9 z. D0 o3 [5 ~9 a! }
bool Work(){. ?, M: _9 }* k1 B
memset( ptr_distance, 0, sizeof( _Distance_Type) * points_range);) K9 k* F3 z. S1 F! p4 @: Z% p2 P
memset( ptrNew_pathLength, 0, sizeof( int) * points_range);5 B, V8 X& T. A+ Y% O- {
for( int i = 0; i < points_range; ++i){
0 m! _! R6 m; M/ i* W# p+ M' [. y9 ]2 m ptr_queue[ i] = i;2 w1 ^! x% F5 b# r* J
}* S6 T1 k+ [5 x, Q u
memset( ptr_isInQueue, true, sizeof( bool) * points_range);: `( l, [3 X: J3 r! v4 Z- l
queue_head = 0;
0 E$ ^$ L4 Z8 J$ y: b- Q queue_tail = points_range;
; `5 m' t; w8 Q4 s //--; e$ d! k4 @: P" w" l1 W* R
int cur, nex, edge;4 H7 y/ D3 x& e6 T) f4 S
while( queue_head != queue_tail){/ Q6 V% X- k% q/ ~- U
cur = ptr_queue[ queue_head ++];2 Q# J2 Y0 w( y
ptr_isInQueue[ cur] = false;
3 O- W! K {) u/ s if( queue_head > points_range){ queue_head = 0;}6 t/ y/ }, a3 O8 n1 R" A$ B
for( edge = ptrRef_graph->Head[ cur]; ~edge; edge = ptrRef_graph->Next[ edge]){
4 k5 |2 x) T6 x1 u: O8 N nex = ptrRef_graph->Vertex[ edge];
3 c8 D0 @4 C* ^2 |* L" u if( ptr_distance[ cur] + ptrRef_graph->Weight[ edge] > ptr_distance[ nex]){" b0 K$ g8 V J% e) B2 o! N6 S4 ^
ptrNew_pathLength[ nex] = ptrNew_pathLength[ cur] + 1;
, L' Z ]4 k4 B/ S: @: g* C if( ptrNew_pathLength[ nex] >= points_range){
. R f/ y2 b6 J, r7 |* u9 n& x return false;
& Y0 v$ n' o% b- }+ {0 s" S6 q }
% O' e0 R: H: h9 u9 [4 S' C( d2 I ptr_distance[ nex] = ptr_distance[ cur] + ptrRef_graph->Weight[ edge];& }; s) T. Q) j* v: n
if( false == ptr_isInQueue[ nex]){
+ \8 {5 G1 a6 W# b ptr_isInQueue[ nex] = true;
2 A4 P4 q. X# H ptr_queue[ queue_tail ++] = nex;
* ^, f0 w3 x) i) d" S5 r if( queue_tail > points_range){ queue_tail = 0;}, e3 ]( A1 e8 R1 J* {
}
/ x7 E4 t% j/ x4 | }
& a& {4 y* i' h) D [ }' O( ~; O9 q1 [: [, P
}2 d; G# z' J/ b" T4 h
return true;
% \# g- W* C. T* ~ }: E& w& n4 J/ z
private:* W* z4 v6 i6 c" n# I# d9 H
const Graph_Weighted< _Edge_Type> * ptrRef_graph;
9 F1 v, R3 R& ~: k( _8 e; ^ int points_range;) c5 |0 Z! z; K: D! I
_Distance_Type * ptr_distance;
- R$ f* f! X" h, R bool * ptr_isInQueue;
. H# b3 Y0 D6 t0 S: a int * ptr_queue;
6 w) a; j0 _+ q( O6 m. j int queue_head, queue_tail;; q. F: y, M, ^! ] M. p+ Z
int * ptrNew_pathLength;% ?/ m% O; g$ m f! }
};
5 N. H/ A4 g8 t$ p9 v//} Minimize_InequalitiesSystem3 Q) w: v5 K: E/ _5 |, ?4 x$ e" _+ {8 g
; i% e+ J* T+ x$ s0 r
Caution. U3 |0 \. f( Q, u
X6 Z9 G2 n3 x" M! n`+` You should never modify the source-code of @Func( Work), otherwise, it means your algorithm must be erroneous.7 ~) E* X9 {6 Z% O/ [4 u
1
% C" J( ?( n5 R* a8 K+ A# C% m$ y" oAnnotation8 U/ }+ U, J3 Z' t2 c2 {9 o
* t3 @% Y7 F% u# Q4 ?% p
`+` @Func( Work)
- b ^% b2 e$ ~/ p3 S) X`1` `@Ret = true` means the Inequality-System is Consistent, otherwise it is Inconsistent (No-Solution).9 D7 ~- [8 N0 {: M" e: e$ }$ @0 ?! h
`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`;9 j( c- q! W. ~& e+ b0 K2 t
`.` In other words, under the premise `all variables xi >= 0`, minimize every variable and also satisfies all relations (i.e., the graph)) p' y' F5 U8 d5 t" B8 H2 [1 s
) o2 K( b0 @0 ?3 J5 f: v. D( r`+` @Var( ptrRef_graph)8 T; ?2 v0 j/ o+ Q- N* K
`.` 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.
- `3 S( o S! c$ }' V* c0 p* _- O( y
数论$ {- t' x$ v. O
矩阵乘法
) K+ n8 [# F! g9 P4 I1 ^1 m//{ MatrixMultiplication-Declaration
0 z, d/ @2 j4 s% x% f& ~- ltemplate< class _Type, int _MaximumLength>1 ]0 ~; @: O: ^3 L' A: X) n P* U
class MatrixMultiplication{* R) u8 g$ F+ J' ?( a2 U
public:
; G8 D( K1 `1 X$ |2 M. ]5 K MatrixMultiplication( _Type);, l- i1 `4 s9 ^% Q5 A+ R: G9 [
void Initialize( int, _Type (*)[ _MaximumLength], const _Type (*)[ _MaximumLength], const _Type (*)[ _MaximumLength][ _MaximumLength], long long);
: r+ I& U' M+ Y& |" zprivate:" L* I6 H4 e2 w5 M f
_Type modulus;5 C6 r; @" j7 R- T) \
int length;
9 C. Y: {3 W, E/ s5 G' D _Type factor[ _MaximumLength][ _MaximumLength];3 s2 Q, g- s4 l0 f2 R
_Type answer[ _MaximumLength][ _MaximumLength];* Q( S3 B+ N% t$ n3 A5 |
_Type temp[ _MaximumLength][ _MaximumLength];$ \' e/ Q( q+ m4 z
//-- variable ends5 @% T( L; M& T9 w! \8 ]) h! J
void matrix_multiplication( _Type (*)[ _MaximumLength][ _MaximumLength], const _Type (*)[ _MaximumLength][ _MaximumLength], const _Type (*)[ _MaximumLength][ _MaximumLength]);
' Z6 _$ M( i7 s( [};
2 I/ ?5 _8 G. b//} MatrixMultiplication-Declaration
/ z% t& U3 B7 b
( J1 Z" k2 L5 Q! c: E0 ^7 ]//{ MatrixMultiplication-Implementation) a4 H2 Z7 c3 |8 _) V" B
template< class _Type, int _MaximumLength> MatrixMultiplication< _Type, _MaximumLength>::MatrixMultiplication( _Type _modulus), b: W5 i; t3 V' O, e0 e; w D
:' \% {. _% k% A% ` L# e
modulus( _modulus){" ~$ ?% _+ Q" l3 {
}( ^8 A: K% R |0 |
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){
9 l# a& L- d$ P: x//<
) t! I5 Q7 \# E3 P$ S( l8 s// @Brief
% P3 c8 \" f) R" x// . `result = dp * (factor ^ k)`;
3 X! y' T j0 e# [) z: v// @Warning4 i/ B. T: B9 I7 x; U5 U
// . Make sure the data of `dp` is `dp[0, ..., _length)`, the data of `_factor` is `[ (0,0) -> (_length-1, _length-1) ]`;: `9 ]5 y' K' T& z
ASSERT_( _k >= 0);! \: _& b+ P c3 O+ b0 z: G$ t
ASSERT_( _length <= _MaximumLength);
& ~. c6 p$ |' a$ U6 o //----
& d5 K! W4 E3 X/ Y length = _length;
3 @9 h+ G5 Y" T! p9 s2 |9 I //--
, d& o1 l( ~0 s0 `6 b memset( answer, 0, sizeof( answer));8 ~0 M7 q- m. I6 d5 v! l* t0 _
for( int i = 0; i < length; ++i){( t8 _! M3 S+ K( i8 E* }8 ^$ Y
answer[ 0][ i] = (* _dp)[ i] % modulus; if( answer[ 0][ i] < 0){ answer[ 0][ i] += modulus;}
1 L8 V0 w) V! o- v8 B }) ~& c: H: ]0 L& ^( w' b5 V
for( int i = 0; i < length; ++i){& y# y. k9 G+ X) N) W& o2 ]( T5 G
for( int j = 0; j < length; ++j){
8 F- c# }" G( z+ G factor[ i][ j] = (* _factor)[ i][ j] % modulus; if( factor[ i][ j] < 0){ factor[ i][ j] += modulus;}+ O! \7 y o* e4 q, D* y
}- E6 X4 L: ~9 {8 v. V
}
" w# l6 z( i% E8 r //--
' M+ u+ f# g) e/ n. O& Q while( _k > 0){
% f" l" P/ Z" ^! A3 s, Y c. s if( _k & 1){* z) m; H" g. ?5 A# I) Z
matrix_multiplication( &answer, &answer, &factor);
# f1 F/ {9 u, L( {( J7 i }
T1 r. w. S+ F U: M _k >>= 1;
( v7 g4 U- G; x9 ~5 Z5 l" g" Z1 r matrix_multiplication( &factor, &factor, &factor);
% `* _5 g% E/ @6 H- l }! o2 ?6 x& w5 g( i3 p" ?/ p& W
//--
+ ]; p+ U% l* ]! l H memcpy( _result, answer[ 0], sizeof( _Type) * length); // the address of `_result` equals to the address of its first-element;9 h7 ^8 {5 z& n- N" |
}
; ]4 E; G1 A* Q0 {, _- P1 Xtemplate< class _Type, int _MaximumLength> void MatrixMultiplication< _Type, _MaximumLength>::matrix_multiplication( _Type ( * _result)[ _MaximumLength][ _MaximumLength], const _Type (* _a)[ _MaximumLength][ _MaximumLength], const _Type (* _b)[ _MaximumLength][ _MaximumLength]){% W/ t" Z& S6 E9 m% G
//<
9 d# M7 c0 a% c7 |: F+ {// @Brief) h! e) X0 B7 d; I% P& B
// . `result = a * b`;
7 L- D9 k$ B: X( H for( int i = 0; i < length; ++i){3 l7 u- u) F! Y7 p+ {+ U
for( int j = 0; j < length; ++j){6 q5 |. i, q7 y% n& C; f/ m
//>> Cuz `result` maybe equals to `a/b`, you need store the result to `temp` not `result`;7 D) J0 d C. c! e1 u5 r0 o
temp[ i][ j] = 0;
, o" r3 `7 y) T2 K! e# G for( int z = 0; z < length; ++z){
) F) N7 b( A4 R# N9 q$ q2 K } temp[ i][ j] += (long long)((* _a)[ i][ z]) * (* _b)[ z][ j] % modulus; if( temp[ i][ j] >= modulus){ temp[ i][ j] -= modulus;}$ p- P4 M5 g- C6 X+ H# R
}
9 w# f) p% N; v. J$ U }
/ t6 z) x$ B8 [9 a4 \ }. v6 O1 q" \/ t, f
memcpy( _result, temp, sizeof( temp));1 V1 u0 \/ \$ W- r
}9 R9 y! t( M2 n. C a. E h$ u
//} MatrixMultiplication-Implementation
7 D( t) X1 E: K! J2 G' S: s2 Y5 J( B0 h8 s% o
@Delimiter
t# q1 u' ?! C. o: f2 l5 i* ^/ N
示例% U+ n& R3 k$ L; s9 ?
2 j# M; C$ j1 J. D9 N, l @$ P3 G( [& Vint Dp[ 4] = {1, 2, 2, 1};
& y1 P4 S( f% N8 V W# Dint A[ 4][ 4] = {{0,1,0,0}, {1,1,1,0}, {0,0,1,1}, {0,0,0,1}};
3 z# A0 c( ^* C7 j n' M) |: GMatrixMultiplication< int, 4> Mat( M);
0 y5 ^2 v) |2 ^( lMat.Initialize( 4, &Dp, &Dp, &A, N - 2);. ?; v. v5 l4 M0 b0 X& n
& n1 i+ {4 q, p- @' M; n$ k
long long ans = (long long)Dp[ 2] * N % M - Dp[ 3];
7 j8 p. p6 h9 X' ~* _) vcout<< ans;0 Y/ N# P$ B& F0 Z
1
. G4 ~9 C2 J" a! C+ W' _+ a2+ E& a6 p1 k# D8 e: U
31 c+ p; v# x7 p+ r- @& L
4
+ I! i7 K- f' u' o! q7 I# }5
" j* q8 Z" j) |+ E5 n68 j/ `8 A( I4 r5 C3 k
7: l ]* B; a. t7 c0 o. R0 t6 t
中国剩余定理4 \& I! N9 H) ?9 {
朴素 CRT+ O5 z# Q6 R* |
//{ CRT-Declaration6 H- P* l( k& Z* J q
template< class _Type> pair< long long, long long> CRT( int, const pair< _Type, _Type> *);
& ~9 ]& W% ^( W8 r. S//} CRT-Declaration
5 {. q2 H0 w" V" T- K' x8 K3 P3 t5 m+ F3 W/ t0 K
//{ CRT-Implementation) ^8 Q4 ]! w+ Q% Z! G/ }
template< class _Type> pair< long long, long long> CRT( int _n, const pair< _Type, _Type> * _arr){% o8 q$ v! P4 D9 X+ k
//<8 O* A( Q' f, p" E/ |
// @Brief
( e& F9 O9 L) X// . Solve the system of `n` Congruence-Equations represented by `arr` (i.e., `? = arr[i].first (% arr[i].second)`);
9 y3 O% f# Z2 A7 e1 l" H// . Once all `arr[?].second` are Pairwise-Coprime, this system must be Solvable (and Infinite-Solutions);
/ |; i5 c8 I% [7 {4 {// . @Define( `(a,m)` = @Return), `a` must in the range [0, m), and the Solutons are $a + kk * m, \forall kk \in \Z$;" j ?) H$ ]1 D: T4 D7 u7 }
// @Warning5 L U, a; b- s
// . Make sure all `arr[?].second` must be Pairwise-Coprime;
& c7 i; s! Z4 U% H# c7 L* z// . Make sure the Product of all `arr[?].second` in the range `long long`;+ L6 I! e8 ^5 H- C
// @TimeCost
* W5 ?# {. v9 B3 g! `" h; X- [2 Y// . $n * 60$;4 i6 c; b# X7 g( T
long long M = 1;
2 B! `# F* I0 O$ L$ p8 T for( int i = 0; i < _n; ++i){
- L& c* l- F8 D ASSERT_( _arr[ i].second >= 1);; o" B8 }$ k5 P- e% ?4 t
M *= _arr[ i].second;
" K5 g, P& k" P- F) T } B: R& n6 ]% t- L8 U5 l
long long answer = 0;; v! J& w: F4 S5 `8 Y) o. u! U
for( int i = 0; i < _n; ++i){1 R6 d* l# Y* E; g+ K. c, H
_Type a = _arr[ i].first % _arr[ i].second; if( a < 0){ a += _arr[ i].second;}7 X: C% o! o/ u/ }1 @4 I
long long m = M / _arr[ i].second;" [1 r& V Z d+ }' |
pair< bool, pair< _Type, _Type> > ret = LCE_BezoutE< long long>( m, 1, _arr[ i].second); // m * `ret.second` = 1 (% _arr[ i].second);
& n. W0 f9 W% g% c ASSERT_( ret.first); // All `arr.second` are not Pairwise-Coprime which rebels the Premise-Of-This-Algorithm (See @Warning);, t" K6 V9 Q2 | |% \
answer = (answer + (long long)a * m % M * ret.second.first % M) % M;4 t5 @, S9 B N; L; Z$ J$ n
}& {% u# E5 o; r `$ y5 d
return {answer, M};7 p- z: N" h+ Y: k. h
}& t9 N: N4 y* v# c# i% J& s1 f p3 E
//} CRT-Implementation8 y8 d9 P3 ?# C8 E! i
5 w1 R, f' n* s3 F5 g; h' ?拓展 CRT_EX4 V$ F/ A7 }6 N( Y
//{ CRT_EX-Declatation
$ w" u' R0 }9 q9 e( wtemplate< class _Type> pair< bool, pair< long long, long long> > CRT_EX( int, const pair< _Type, _Type> *);
% h$ p6 ~# w7 j8 p% t//} CRT_EX-Declatation0 s1 [' n b ?: j% @* F
, M. e. |+ s- J6 W0 p, y& c
//{ CRT_EX-Implementation
4 }" N' n& }7 G2 Dtemplate< class _Type> pair< bool, pair< long long, long long> > CRT_EX( int _n, const pair< _Type, _Type> * _arr){5 A# J- B2 K/ y
//<
% v2 a4 p( b1 y; J; ?// @Brief' n. i( {6 M/ U# v+ n) I3 |
// . Solve the system of `n` Congruence-Equations represented by `arr` (i.e., `? = arr[i].first (% arr[i].second)`);
* Z6 p5 N: c7 j' b% _3 f// . @Define( `(r1, (r2,r3))` = @Return);+ a+ ~8 S9 z, E( P: f% f
// 0( r1=false): There is No-Solution;! L3 i8 f1 ?* d' j. H
// 1( ELSE): The Solutons are `r2 + kk * r3, $\forall kk \in \Z$`, and `r2` must in the range [0, r3);: j' Z9 I1 L5 j- Z$ O
// . All `arr[?].second` maybe not Pairwise-Coprime (which differs from `CRT`);
5 s1 {" L6 k6 x* k6 l3 O9 q+ `// @Warning
* `8 G4 R. N2 B' N# o& h// . Make sure the LCM (Least-Common-Multiple) of all `arr[?].second` in the range `long long`;
) R. @2 I9 t. [- L- t' U// @TimeCost
# D) f0 e; k# ]* `// . $n * 60$;
/ l! L& C) X3 w0 Y2 \) h1 q pair< bool, pair< long long, long long> > answer;0 v# X! w' O% r) X6 b6 p' c ~
long long A, M;8 W5 ?8 a" |* Y
for( int i = 0; i < _n; ++i){; ]/ g5 k9 v( p4 c
_Type a = _arr[ i].first;
5 S6 g& R! c% \( T4 ~ a %= _arr[ i].second; if( a < 0){ a += _arr[ i].second;}
( I% a; }6 H- J; A4 {' a //--
# i, ^7 f1 Z. {/ S; b$ r. P if( i == 0){
3 {; K. |, v/ ?2 {- m6 X, W A = a, M = _arr[ i].second;* Z. N' Z+ {5 ]0 _# H" f
continue;. S9 i% _- ^$ k% I0 a
}
/ e( o" K+ D% B# Q! ? pair< bool, pair< _Type, _Type> > ret = LCE_BezoutE< long long>( M, a - A, _arr[ i].second);
0 h" x8 Z" J/ O6 `4 e9 Q- G O( N0 l9 w if( false == ret.first){
, h/ A# f0 s9 h# Z- U answer.first = false;; r) e: J% s, S3 H
return answer;
s$ t2 q0 O/ H# q2 V0 Q7 r }
' t$ W! ^2 s! }# q3 P. P, A! u, _ _Type gcd = _arr[ i].second / ret.second.second; if( gcd < 0){ gcd = -gcd;} // The GCD of `M` and `_arr[i].second`;
' w. N* s3 Y7 e" B) K# J, Z long long new_M = M / gcd * _arr[ i].second; // LCM1 _6 e0 g8 ?3 j5 x/ e+ B/ p7 y; ]
A = (A + ret.second.first * M % new_M) % new_M;3 O# A! H& P' J Z! |- A
M = new_M;) W# J' ?4 l5 n: n; J
}
; I" W' W A3 P1 u4 }+ H answer.first = true;$ \( \: p/ \8 W8 B' l: T
answer.second.first = A;
; }: B4 I9 E- T% v# L0 y answer.second.second = M;7 L( t. H% g- s, y+ T
return answer;
0 ?: X P9 k/ B7 n3 `}3 {* W: f2 s6 p
//} CRT_EX-Implementation' t6 q. o' k* {" P" k& f M9 R8 a4 I
1
) @" h1 I% p, E+ T" P( k: ?裴蜀方程 BezoutE
' \( `" W6 k: V) g//{ BezoutE-Declaration
$ E- d4 ?( e& V8 w, ?7 G3 Dtemplate< class _Type> pair< bool, pair< pair< long long, _Type>, pair< long long, _Type> > > BezoutE( _Type _a, _Type _b, _Type _c);
$ K8 E5 \5 W/ ~$ t9 E- j" E//} BezoutE-Declaration
E5 N, `, g8 q0 z+ ^6 P+ n1 I5 ?0 g8 n
//{ BezoutE-Implementation% \2 Y2 E2 _4 b4 ~! E1 y; W( f
template< class _Type> pair< _Type, pair< long long, long long> > BezoutE_extendedGCD( _Type _a, _Type _b){
, h( Y7 O9 q) ~5 J7 G//<
; S2 u$ N( s6 G/ _; f; w* G. V// @Private
: m/ E5 E5 T6 ^+ ~ E! g0 z# r// @Warning1 J9 |' B ]# D% h1 A
// . Make sure `a,b >= 0`, Not-Both-Be-`0`;1 |* F* F) G8 g) Z, i1 q/ A; |
if( _b == 0){
; O$ f" h& r& C3 O- T7 S return {_a, {1, 0}};8 W( I7 K1 {3 X- b( |5 p+ K
}
& ?+ }% Y; R# `2 U auto pre = BezoutE_extendedGCD( _b, _a % _b);
: _; K/ b$ a5 w: R; l; V+ x: [+ x8 h: w auto xp = pre.second.first;' J0 K6 N* l/ r6 R
auto yp = pre.second.second;. ~2 y% w9 _* k8 A6 q# B4 r
return {pre.first, {yp, xp - yp * ( _a / _b)}};
: f6 n8 Z8 k. f; \+ B1 K3 Y `2 f};( K. b: k" F/ ^/ J; ~ J) _) L
template< class _Type> pair< bool, pair< pair< long long, _Type>, pair< long long, _Type> > > BezoutE( _Type _a, _Type _b, _Type _c){
3 A$ X6 C7 Z' l! |1 G//<
c. Y8 k' f! }* z( s// @Brief0 s# L3 {& w" E9 h
// . Solve the equation `xx * a + yy * b = c`, @Define( `(r1, ((a1,m1), (a2,m2)))` = @Return)`;
+ C4 j9 w Z+ y8 m7 k+ ]9 O% E// 0( r1=false): There is no Solution;4 O- G' Z, k# u2 K# @
// 1( ELSE): The General-Solutions are `(a1 + k * m1, a2 - k * m2) $\forall k \in \Z$`;' D- p# Q8 C4 D1 t) g3 |9 @
// @TimeCost2 f$ w7 _9 E5 d
// . $\ln(a)$;0 u4 A; v. \( h2 c" V/ K5 Q9 F
// @Warning
4 G: r: A( X7 m! W// . Make sure `a != 0`, `b != 0`;
$ v* @ r" B1 G1 U7 [# l, { ASSERT_( (_a != 0) && (_b != 0));
, A) t+ T+ e3 c7 u. Y pair< bool, pair< pair< long long, _Type>, pair< long long, _Type> > > answer;
U4 t& E9 E% h9 r* p ^ bool neg_a = false, neg_b = false;! F8 g% l6 G, A \+ X2 p$ g+ n, L
if( _a < 0){ neg_a = true; _a = -_a;} // `x * a + y * b = c` -> `(-x) * (-a) + y * b = c`;% l( E1 K! W/ s4 E
if( _b < 0){ neg_b = true; _b = -_b;} // `x * a + y * b = c` -> `x * a + (-y) * (-b) = c`;
( s$ k! v" S( K, R4 X8 R //--% b: ^% Q% [! f9 U& _3 z
pair< _Type, pair< long long, long long> > ret = BezoutE_extendedGCD( _a, _b);; n7 {# E! k+ p" o# t I
if( _c % ret.first != 0){' [' `% k( r' q) L, Y
answer.first = false;
6 }% r# N; y4 L( l. ~% L& g return answer;
$ x* m Y' ], G4 y3 Q }
# x% e1 Y# Z) N6 z answer.first = true;& @8 K. C+ g O8 k
answer.second.first.first = ret.second.first * (_c / ret.first);6 D6 u3 V/ A s, M
answer.second.first.second = _b / ret.first;' b3 w' q5 G- K- e& \
answer.second.second.first = ret.second.second * (_c / ret.first);- \* B0 l' o: ]$ @" s! A% h
answer.second.second.second = _a / ret.first;
/ T0 M1 L7 `# o" t if( neg_a){ answer.second.first.first = -answer.second.first.first;}
4 y( k* K1 }# `( s8 i% |6 B' a if( neg_b){ answer.second.second.first = -answer.second.second.first;}( k- [( I* I: {) k9 d+ w8 a1 E$ V
return answer;
: ` \0 D( ~2 E/ z}. E6 o# w' d7 N0 J4 _/ j
//} BezoutE-Implementation" B ?4 ?4 U1 u: Q) }% P
! d6 G3 q# J6 B8 r4 I
线性同余方程 LCE, t2 A% V, K! Z4 x D# O. X9 z# t
裴蜀方程法 LCE_BezoutE
2 K% Q! ~& o3 {/ u8 D9 S0 z5 N* S//{ LCE_BezoutE-Declaration
3 z! B2 e5 e$ s$ q# Htemplate< class _Type> pair< bool, pair< _Type, _Type> > LCE_BezoutE( _Type _a, _Type _b, _Type _mod);8 k% v S) B0 L9 o h
//} LCE_BezoutE-Declaration
& V7 s4 O% f5 x! C V7 p6 ^9 s: J: x; k. S8 x3 T+ x
//{ LCE_BezoutE-Implementation- J) u& R( \! A* Q) |2 \
template< class _Type> pair< bool, pair< _Type, _Type> > LCE_BezoutE( _Type _a, _Type _b, _Type _mod){& M2 m. H: U6 |, }
//<
8 ?0 ?) M' s, \9 C// @Brief; O# v [ z7 q/ [1 M3 K# L$ b. J
// . Solve the Congruen-Equation `a * ? = b (% mod)` where `?` is @Return; @Define( `(r1, (a1,m1))` = @Return);9 A: q7 L7 E; ?4 A7 f6 z7 P$ P
// 0( r1=false): There is No-Solution;
5 w) R4 O G$ A; C+ T+ `// 1( ELSE): The General-Solutions are `a1 + k * m1, $\forall k \in \Z$`, and `a1` always in the range [0, m); G& r6 _$ H- O$ |. i0 M
// @TimeCost
/ H& ~4 v/ D- r" G6 r// . $\ln(_a)$;
! n* h) N) G. g' T ASSERT_( _mod >= 1);' T7 H+ l# {. b* ~
pair< bool, pair< _Type, _Type> > answer;
; H8 l. H. V/ r1 M% Q _a %= _mod; if( _a < 0){ _a += _mod;}3 O( I: c# r/ n
_b %= _mod; if( _b < 0){ _b += _mod;}
- W* K. j& H, c& n9 m if( _a == 0){9 Y; e0 C6 V* Y. _2 j4 H" l
if( _b == 0){ K: z3 H# ~" t" P+ D. L* G
answer.first = true;" |4 _; I! i& e3 m; q; a* m3 J, K
answer.second.first = 0;4 |' o' e' |8 q) L& G
answer.second.second = 1;
. ^0 C0 U3 n4 G( s; u/ N return answer;( m5 i2 i# t, h% m. \& r7 E8 ]
}
5 N* C T' p; y6 ^' g else{
6 J( k" W& }7 A; A2 g' u0 ] answer.first = false;
x! S$ f. O: z- m return answer;! J% J9 C2 O& H
}/ D) f* `4 \% z+ v
}9 @" \& m/ k9 ~5 V
_Type gcd = GCD< _Type>( _a, _mod);1 T6 e# B. F* e5 ^4 L* S
pair< bool, pair< pair< long long, _Type>, pair< long long, _Type> > > ret = BezoutE< _Type>( _a, _mod, gcd);1 e8 W; R5 d* F3 [
ASSERT_( ret.first);, g! h5 R- L) m" H: i- Y! `4 x
if( _b % gcd != 0){8 [. P3 C0 E3 n
answer.first = false;/ V" o$ D% ]& S5 g5 t% ^# u
return answer;
4 f: {: a3 H+ f+ R T2 a }
" x; ?& _# o! y) S answer.second.second = _mod / gcd;
) N$ f3 F- l5 ?1 | answer.second.first = Binary_Multiplication< _Type>( ret.second.first.first, _b / gcd, answer.second.second);0 Y, A" L5 s) m* D$ u- C6 z
answer.first = true;
1 ~( m1 \. [; q8 S" M return answer;; R! C# n* b" U: Q4 u7 V
}0 @# K: f' k# J! V8 b0 v8 o7 R
//} LCE_BezoutE-Implementation
4 A- x" t, N6 I/ K9 J7 T0 S& a! a: ~) f: P4 P7 \- H% {8 F% \
高斯消元线性方程组0 N/ F2 u$ Y; H% p
//{ Gaussian elimination
2 r; w" F, Z( \; v+ u0 a/ Edouble Aug[ 105][ 105]; //< @Abbr( augmented matrix)
. i. q0 q ^$ d+ k7 m3 ^8 rint Gaussian_elimination( int _m, int _n){
% F/ d/ |6 n- k# N: L9 }: e//< @Par( _m): the number of equations9 X% t* b8 W% n. A
//< @Par( _n): the number of variables
8 v" J8 s1 d/ \' B& o//< @Return: (0 is unique solution), (1 is infinitely many), (-1 is no solution)
- Q1 Y8 A* q6 _, D6 {, i: z: ^ int rank = 0;+ g- U4 u& B8 f, o9 _' E5 q
for( int col = 0; ( col < _n) && ( rank < _m); ++col){( ]) u4 b; v \. n, H
int max_row = rank;
3 w' ^/ P. S, B# Z: e for( int row = rank + 1; row < _m; ++row){% q- N. t2 q( _$ o
if( fabs( Aug[ row][ col]) > fabs( Aug[ max_row][ col])){
4 Z, }5 \4 A8 y: ~) g max_row = row;# L1 a9 w9 ?3 i4 g2 j% p3 ~/ O
}
5 {5 ~; i) m+ I$ X7 J7 I+ d+ y }
- d6 K6 d1 g0 a if( 0 == Db_cmp( fabs( Aug[ max_row][ col]), 0, Epsilon)){
! r; X) c, Z2 C6 K3 u //* either no solution, or infinitely many.# C- _ M2 P Q/ i% D# P" m8 U6 j
continue;
% Q7 t3 _, E. E3 c1 M }) U, q& E/ u: d9 y" e. ^
//{ swap two rows
4 w, t h% g% J; x4 U for( int c = 0; c < _n + 1; ++c){
, u0 b' U0 T# _' l- L- V swap( Aug[ max_row][ c], Aug[ rank][ c]);- e- ?5 B1 h" D; `6 O- D$ {5 F
}: @) `6 d4 w5 }$ k+ ~
//}# D @1 m3 w+ K, @- \
//{ make current pivot to `1`
7 J, y* H1 }) A( |: O- t- t/ o" I for( int c = _n; c > col; --c){
1 U K1 W1 h3 J, h Aug[ rank][ c] /= Aug[ rank][ col];
, G$ Q/ D# T8 R9 \' \9 @ }
+ ~1 F% d7 K! F | Aug[ rank][ col] = 1;- L7 \' T( M% |0 b! i* b/ c
//}
) R" K6 L; t% r2 p) \ n //{ make all rows below current pivot in the same column to `0`
4 A. H- f, e7 Q5 U& w& ^* B, q5 \ for( int r = rank + 1; r < _m; ++r){
5 p( z3 K! p& y* q+ X0 J if( 0 == Db_cmp( fabs( Aug[ r][ col]), 0, Epsilon)){
: _, d$ o) p1 [* G& Y6 z continue;
4 w) S+ B$ Y- l }
. Z& q/ Z0 X; q9 U& r for( int c = _n; c > col; --c){
( R* R9 A" ?) ~: M% ^/ S5 g+ ^ Aug[ r][ c] -= Aug[ r][ col] * Aug[ rank][ c];
6 |; e; d; z" i" k }
. r! T2 Y6 B: r, b6 X: u) z Aug[ r][ col] = 0;
2 g' M1 d3 a4 r }
, q. t2 q' S# \, T6 D0 d ++ rank;, @7 [# i7 n' B
}
3 _6 {/ }8 R* q3 t& L a `% ` //--1 N4 Q( r( B2 G: i7 M
for( int r = rank; r < _m; ++r){% w5 O7 t; N: M3 W. a0 y
if( 0 != Db_cmp( Aug[ r][ _n], 0, Epsilon)){, [' d: l. Q3 G, @' k
return -1;: _8 J! D* l8 [" \* y0 s
}# v% c1 L6 q7 F3 w' Q; g, f
}
4 e N7 f9 F! W3 D$ m& Z6 j if( rank != n){! \" }6 F% t1 \8 @
return 1;
# X$ Y! k% P3 ^( m }. x+ I( y, X2 g6 O- O
//> the upper-left `_n * _n` submatrix of `Aug` is a identity-matrix( x! }0 N+ C; {
for( int r = rank - 1; r > 0; --r){7 k- A6 N$ {" x% l: E: Z8 ?
for( int rr = 0; rr < r; ++rr){- F' l* C4 A f7 _ E1 i, G! H7 E
if( 0 == Db_cmp( Aug[ rr][ r], 0, Epsilon)){$ e# K" s; N3 _* P' l- F. d, Q
continue;
& X8 ~" Q& W0 q. U1 n }0 P( Q" C. [6 M
Aug[ rr][ _n] -= Aug[ rr][ r] * Aug[ r][ _n];' Q: n: r) U- W: h$ _1 h
Aug[ rr][ r] = 0;
' |0 q/ K- K! s3 o1 a9 F/ { }
# n6 U( J- X: c6 S9 G: u8 Y } L; |" p5 \: D% D- m6 L
return 0;
+ T7 O# K# l% a5 v" @}
7 Z3 L4 q* Z- I: j//} Gaussian elimination4 ]! Z+ Q+ J$ _
) ?) S2 A4 Y7 f' O0 F
. Z0 [; V8 a& l/ p8 s
|
|