语法

数据类型

整型:原码、反码与补码

  • 首先把整数的真实数值称为真值。

  • 原码:最高位表示符号(\(0=+,1=-\)),后面是其绝对值的二进制表示。

  • 反码:正数的反码等于原码,负数的反码等于原码除符号位外取反所得。\(0\) 见下。

  • 补码:正数和 \(0\) 的补码等于原码,负数的补码等于其反码 \(+1\) 。允许向符号位进位,进位溢出相当于自然溢出(即对类型大小上限取模)。

  • 目的:

    • 原->反:标记符号位非常麻烦。设法让其参与运算。可以使真值正确,但是 \(0\) 的符号不对(\(00000000\)\(10000000\))。在计算机意义下并不美妙。

    • 反->补:平移解决上面的 bug。顺便使得 \(10000000=-128\),这也就是为什么负数比正数多了一个。

  • 没有规定必须用补码实现整型!!!

  • 不过,至少我没见过这种鬼才实现。

整型:大端与小端

  • 我们可以把整数的较高位存在较靠前的位上,也可以把较低位存在较靠前的位上。

  • 优劣性?目前不了解。据称这是历史遗留问题,现在各种语言/环境(广义的,包括 HTML,MAC,...)仍然使用着不同的表示方式。

  • C++ 中的影响?几乎没有。唯一有影响的可能是高精度类型强转低精度类型的结果,但就我目前的了解:

    • 浮点型的强转是降低精度以匹配(一般是抛弃太小的小数)。

    • 整形强转无论大小端一定抛弃高位。

浮点型:精度

  • __float128 的精度比 long double 高。它的位数在事实上对标 __int128,为 \(128\text{bit}\),即 \(16\text{byte}\)

  • 理由?嗯...众所周知,__ 类都不是 ISO C++ 规定中要实现的东西(如果实现,也不规定怎么实现)。

  • 但是,long double 是 ISO C++。<cfloat> 或者说 <float.h> 库中有它相关的声明,所以它是一定要实现的。

  • 然而它的实现标准很有趣:最坏情况下和 double 完全一样,都是:

    • 最大值至少为 \(10^{308}\)

    • 最小值(比 \(0\) 大的)至少为 \(10^{-308}\)

    • 精度(定义为能表示的比 \(1\) 大的最小数和 \(1\) 的差)至少为 \(10^{-9}\)

  • 换言之,在某些毒瘤实现中,可能 long double 就是 double 的等价类,甚至只是一个同义关键字。

  • 不过,在较常见的实现中,long double 要么是 80 bit(15-1-64,分别是 \(2\) 的指数、正负、有效数字部分),要么在 64 bit 内实现了比 double 更高的精度(但值域一样)(怎么做到的??)。所以可以期望通过使用它来提高精度——但也可能会导致常数过大而被卡。

浮点型:除零与判等

  • 小标题中的除零是一种非法操作(尽管在浮点数中并不非法)的称呼,按照数学语言应该是除以零。

  • 好了说回来。众所周知,浮点型除了常规数值之外,还有两个特殊值:\(inf\)\(nan\)

  • 两者怎么实现(或者说二进制下的表示)我不了解,不过两者分别表示的东西我们还是知道的:

    • \(inf\):无穷大。通常来源于非零数除以 \(0\),或 \(inf\) 与非 \(inf\) 数的运算。

    • \(nan\):非法。通常来源于 \(0/0\)\(inf-inf,inf/inf\),以及所有含 \(nan\) 的运算。

  • 说回判等。受掉精度(可能还有随机扰动)的影响,对浮点型我们通常认为若 fabs(x-y)<eps,则 \(x=y\)。那么,\(inf\)\(nan\) 呢?

  • 两个 \(inf\) 彼此相等。这里的相等,指的是对他们做 == 的二元运算会返回 \(true\)

  • 但是!\(inf-inf=nan\),所以 fabs(x-y)<eps 的结果为 \(false\)

  • 故不要指望对竖线用斜率判共线,没戏的。

  • 当然,可以加一个 == 的补丁...可话又说回来,万一不保证点彼此不同呢?\(nan\) 参与的所有运算都是非法运算,语句 nan>nan,nan==nan,nan<nan 的返回值全部是 \(0\)

  • 所以,如果碰到竖线,请老老实实特判。换言之,记住斜率不是万能的,共线总是得特判!

C 库函数

memset

void * memset ( void * ptr, int value, size_t num );

  • 原理是把中间那个数字的十六进制表示(当然是补码意义下的)反复地放到对应数据类型的每 16 位上。

  • 对于 int 型,我们通常使用这些:

    • \(0\to 0\)

    • \(-1\to -1\)

    • \(127\to 2139062143\)

    • \(128\to -2139062144\)

    • \(63\to 1061109567\)

    • \(192\to -1061109568\)

  • 最后这两个的目的是加不炸的 \(inf\)。事实上,\(63\) 的结果就是 \(\text{0x3f3f3f3f}\)\(192\) 的结果就是 \(\text{0xc0c0c0c0}\)

memcpy

void * memcpy ( void * destination, const void * source, size_t num );

  • 原理类似 memset,就不多说了。

fill

template <class ForwardIterator, class T> void fill (ForwardIterator first, ForwardIterator last, const T& val);

  • 看起来是和上面那两个不一样的原理呢...不过使用起来是一样的。

iota

template <class ForwardIterator, class T> void iota (ForwardIterator first, ForwardIterator last, T val);

  • 同上。

unique

unique(iterator first,iterator last)

  • 去重 \([first,last)\) 之间的元素(实质是把重复的都放到后面)。复杂度 \(O(n)\)

  • 返回值是去重后的末元素后处指针。

  • 如果想要获得末元素的下标,应当这样:top=unique(a,a+n)-a

  • 当然也可以从下标 \(1\) 开始,不过减去的时候也要对应减去。

mt19937

mt19937 _rand(chrono::steady_clock::now().time_since_epoch().count()^271828)

  • 调用此声明可以创建一个 mt19937(基于梅森素数 \(2^{19937}-1\) 的随机数类)的随机函数,括号内的东西是种子。

  • 这里选择使用高精度时间+扰动作为种子。

  • 该随机函数返回值为 int 范围内的自然数,如果需要 ll 范围的可以用 mt19937_64

  • 随机性超好而且比 rand() 快。

random_shuffle 与 shuffle

random_shuffle(iterator first,iterator last,RandomNumberGenerator&& gen)

  • 第三个参数是我从 C++ Ref 直接搬过来的,所以显得很怪。

  • \([first,last)\) 的元素随机打乱。打乱方式和随机化-随机打乱中的算法完全相同,只是将数组下标改为从 \(0\) 开始的。

  • 故那个 gen 就是一个随机数发生器罢了。可以省略,但请一定手动实现它!默认的 rand() 即使赋了 srand(),表现也非常差。推荐使用 mt19937

  • 具体来讲,第三个参数应当是一个如下的函数:

il int myrand(int i){return _rand()%i;}

  • 即读入一个 int \(i\),返回一个 \([0,i)\) 之间的随机数。调用时应该这么写:

random_shuffle(first,last,myrand)

  • 是的,myrand 不加括号。

  • 需要指出的是,这里之所以是 int 而非整型的主要理由是不可能开出一个长度炸 int 的数组(bitset 能不能 random_shuffle 我没试过)。

  • 但同样需要指出的是,rand() 的实现只要求它返回一个 \([0,32768)\) 之间的整数,所以在数组大小大于这个上界的时候,不加 RandomNumberGenerator 的打乱效果奇差无比。

  • shuffle 的效果据称比 random_shuffle 好很多,但我不了解其内部实现。就使用而言,这样:

shuffle(first,last,_rand)

  • 嗯把那个 mt19937 声明的随机函数不加括号地传进去就好。

字典序(姑且放这里)

For(i,0,min(a.size(),b.size())-1)
    if(a[i]!=b[i]) 
		return a[i]<b[i];
return a.size()>b.size();

STL 容器

priority_queue

priority_queue<类型名,容器<类型名>(,比较结构体)>

  • 其中的容器可以使用 vector 或 deque,通常使用前者因为 deque 非常慢而且空间大。

  • 默认为大根堆(越小的越靠后),想改变可以传 cmp 或者逆向重载 < 运算符。

  • 如果是定义了小于号的类型,可以不要比较结构体。这是较为常用的方式。

  • 如果想用比较结构体,譬如说想对 struct number 实现多个比较逻辑不同的 priority_queue:实现一个 struct,内置一个 operator() 的实现。

struct number{
	int k; ll v;	
};
struct cmpa{
	il bool operator()(number a,number b){return a.v!=b.v?a.v<b.v:a.k>b.k;}
};
struct cmpb{
	il bool operator()(number a,number b){return a.v!=b.v?a.v<b.v:a.k<b.k;}
};
  • 复杂度:\(O(\log_2 n)\)

set 与 multiset

  • s.~set()s.~multiset() :销毁集合,释放内存。

  • 不建议使用,因为 set 与 multiset 总是在元素被删除时释放对应内存,clear 可以起到相同效果。

  • 相较之下,解构后的集合相当于没有被声明过(即之后任意的调用都是 UB),首先不能多组数据重复使用,然后有可能导致莫名 RE。

u_map 与 u_set

  • 自定义哈希函数:
struct my_hash{
    static ull splitmix64(ull x){
        x+=0x9e3779b97f4a7c15;
        x=(x^(x>>30))*0xbf58476d1ce4e5b9;
        x=(x^(x>>27))*0x94d049bb133111eb;
        return x^(x>>31);
    }

    size_t operator()(ull x) const {
        static const ull FIXED_RANDOM = chrono::steady_clock::now().time_since_epoch().count();
        return splitmix64(x + FIXED_RANDOM);
    }
};
  • 第一个函数无所谓,就是一个固定的哈希生成器。第二个是需要实现的哈希函数。将此结构体作为最后一个参传入对应 STL 即可。

  • 对,就是 splitmix64 算法...虽然是公开的,但考虑到它优秀的哈希强度和 chrono 带来的随机性,应该没人卡得掉?

vector 与 basic_string

  • emplace_backpush_back 快。

  • vector 远比你想象得占空间。用 size 命令实测得到空 vector 会占 24 个类的空间。

内置的重载运算符

bool operator<(const 结构体名 &b) const{
	if(r==b.r) return l<b.l;
	return r<b.r;
}
  • 随便举了个例子。

  • 其中的 l,r 可以写成 this->l,this->r(倒不如说这其实是简写)。

  • this 是本元素的指针,& 的那个是右边那个。对于 += 等运算符也是一样的。

高精度

  • 原理为竖式加减,高精除高精例外(目前已知的(实践意义的)实现基于二分+减法模拟除法)。

  • 下面给出一份可用的压位实现,缺陷:未实现高精除高精,对任意进制的处理很差(各种只能转 \(10^9\) 进制的函数没有标明),末尾的转二进制输出很迷惑,宏定义已经过期(其中的 For 现在应为 Fort)。

namespace bigint_support{
	const ll M=1e9;
	const int maxlen=2e3,uselen=2e3;
	struct bigint{
		ll a[maxlen]; int len;
		bigint(){memset(a,0,sizeof(ll)*uselen),len=0;}
		il bool empty()const{return !len;}
		il ld lg()const{return len?(len-1)*9+log10((long double)a[len-1]):0;}
	};
	
	il void big9rd(bigint &A){
		A=bigint();
		static string in; cin>>in;
		for(int i=in.size()-1,j;;i=j-1,++A.len){
			j=mymax(0,i-8);
			For(l,j,i) A.a[A.len]=(A.a[A.len]<<3)+(A.a[A.len]<<1)+(in[l]^48);
			if(!j) break;
		}
		A.len+=A.a[A.len]>0;
		return;
	}
	il bigint big9rdr(){
		static bigint ret; ret=bigint();
		static string in; cin>>in;
		for(int i=in.size()-1,j;;i=j-1,++ret.len){
			j=mymax(0,i-8);
			For(l,j,i) ret.a[ret.len]=(ret.a[ret.len]<<3)+(ret.a[ret.len]<<1)+(in[l]^48);
			if(!j) break;
		}
		ret.len+=ret.a[ret.len]>0;
		return ret;
	}
	il void l2big(bigint &A,ll B){
		A=bigint();
		for(;;++A.len){
			A.a[A.len]=B%M,B/=M;
			if(!B) break; 
		}
		A.len+=A.a[A.len]>0;
		return;
	}
	il bigint l2bigr(ll B){
		static bigint ret; ret=bigint();
		for(;;++ret.len){
			ret.a[ret.len]=B%M,B/=M;
			if(!B) break;
		}
		ret.len+=ret.a[ret.len]>0;
		return ret;
	}
	il void s2big(bigint &A,const string &s){
		A=bigint();
		for(int i=s.size()-1,j;;i=j-1,++A.len){
			j=mymax(0,i-8);
			For(l,j,i) A.a[A.len]=(A.a[A.len]<<3)+(A.a[A.len]<<1)+(s[l]^48);
			if(!j) break;
		}
		A.len+=A.a[A.len]>0;
		return;
	}
	il bigint s2bigr(const string &s){
		static bigint ret; ret=bigint();
		static string in; cin>>in;
		for(int i=s.size()-1,j;;i=j-1,++ret.len){
			j=mymax(0,i-8);
			For(l,j,i) ret.a[ret.len]=(ret.a[ret.len]<<3)+(ret.a[ret.len]<<1)+(s[l]^48);
			if(!j) break;
		}
		ret.len+=ret.a[ret.len]>0;
		return ret;
	}
	
	il void wt9(ll x){
		static char wtst[10];
		static int wttp=0;
		while(x>9) wtst[++wttp]=x%10|48,x/=10;
		wtst[++wttp]=x|48;
		while(wttp<9) wtst[++wttp]='0';
		while(wttp) pc(wtst[wttp--]);
		return;
	}
	il void big9wt(const bigint &x){
		static bool flag; flag=0;
		for(int i=x.len-1;~i;--i)
			if(flag) wt9(x.a[i]);
			else if(x.a[i]) flag=1,wt(x.a[i]);
		if(!flag) pc('0'); return;
	}
	il void big9wtk(const bigint &x){big9wt(x),pc(' '); return;}
	il void big9wth(const bigint &x){big9wt(x),pc('\n'); return;}
	
	il bool operator==(const bigint &A,const bigint &B){
		if(A.len!=B.len) return false;
		for(int i=A.len-1;~i;--i)
			if(A.a[i]!=B.a[i])
				return false;
		return true;
	}
	il bool operator!=(const bigint &A,const bigint &B){
		if(A.len!=B.len) return true;
		for(int i=A.len-1;~i;--i)
			if(A.a[i]!=B.a[i])
				return true;
		return false;
	}
	il bool operator<(const bigint &A,const bigint &B){
		if(A.len!=B.len) return A.len<B.len;
		for(int i=A.len-1;~i;--i)
			if(A.a[i]!=B.a[i])
				return A.a[i]<B.a[i];
		return false; 
	}
	il bool operator>(const bigint &A,const bigint &B){
		if(A.len!=B.len) return A.len>B.len;
		for(int i=A.len-1;~i;--i)
			if(A.a[i]!=B.a[i])
				return A.a[i]>B.a[i];
		return false; 
	}
	il bool operator<=(const bigint &A,const bigint &B){
		if(A.len<B.len) return true;
		if(A.len>B.len) return false;
		for(int i=A.len-1;~i;--i)
			if(A.a[i]!=B.a[i])
				return A.a[i]<B.a[i];
		return true;
	}
	il bool operator>=(const bigint &A,const bigint &B){
		if(A.len<B.len) return false;
		if(A.len>B.len) return true;
		for(int i=A.len-1;~i;--i)
			if(A.a[i]!=B.a[i])
				return A.a[i]>B.a[i];
		return true; 
	}
	
	il void operator<<=(bigint &A,const int B){
		if(B>=uselen){A=bigint(); return;}
		static int mvlen; mvlen=mymin(uselen-B,A.len);
		memmove(A.a+B,A.a,sizeof(ll)*mvlen);
		memset(A.a,0,sizeof(ll)*mvlen);
		A.len=mvlen+B; return;
	}
	il bigint operator<<(const bigint &A,const int B){
		static bigint ret; ret=bigint();
		if(B>=uselen) return ret;
		static int mvlen; mvlen=mymin(uselen-B,A.len);
		memcpy(ret.a+B,A.a,sizeof(ll)*mvlen);
		ret.len=mvlen+B; return ret;
	}
	il void operator>>=(bigint &A,const int B){
		if(B>=uselen){A=bigint(); return;}
		static int mvlen; mvlen=A.len-B;
		memmove(A.a,A.a+B,sizeof(ll)*mvlen);
		memset(A.a+B,0,sizeof(ll)*mvlen);
		A.len=mvlen; return;
	}
	il bigint operator>>(const bigint &A,const int B){
		static bigint ret; ret=bigint();
		if(B>=uselen) return ret;
		static int mvlen; mvlen=A.len-B;
		memcpy(ret.a,A.a+B,sizeof(ll)*mvlen);
		ret.len=mvlen; return ret;
	}
	
	il void operator+=(bigint &A,ll B){
		if(A.empty()){l2big(A,B); return;}
		static int i;
		for(i=0;B;++i){
			B=B+A.a[i];
			A.a[i]=B%M,B/=M;
		}
		chkmax(A.len,i);
		return;
	}
	il bigint operator+(const bigint &A,ll B){
		if(A.empty()) return l2bigr(B);
		static bigint ret; ret=A;
		static int i;
		for(i=0;B;++i){
			B=B+ret.a[i];
			ret.a[i]=B%M,B/=M;
		}
		chkmax(ret.len,i);
		return ret;
	}
	il void operator+=(bigint &A,const bigint &B){
		if(A.empty()){A=B; return;}
		static ll now; now=0,chkmax(A.len,B.len);
		for(int i=0;i<A.len;++i){
			now=now+A.a[i]+B.a[i];
			if(now<M) A.a[i]=now,now=0;
			else A.a[i]=now-M,now=1;
		}
		if(now) A.a[A.len]=now,++A.len;
		return;
	}
	il bigint operator+(const bigint &A,const bigint &B){
		if(A.empty()) return B;
		if(B.empty()) return A;
		static bigint ret; ret=bigint();
		static ll now; now=0,ret.len=mymax(A.len,B.len);
		for(int i=0;i<ret.len;++i){
			now=now+A.a[i]+B.a[i];
			if(now<M) ret.a[i]=now,now=0;
			else ret.a[i]=now-M,now=1;
		}
		if(now) ret.a[ret.len]=now,++ret.len;
		return ret;
	}
	
	il void operator-=(bigint &A,ll B){
		static ll now;
		for(int i=0;B;++i){
			now=B-A.a[i];
			if(now<=0) A.a[i]=-now,B=0;
			else{
				if(now%M) A.a[i]=M-now%M,B=now/M+1;
				else A.a[i]=0,B=now/M;
			}
		}
		while(A.len && !A.a[A.len-1]) --A.len;
		return;
	}
	il bigint operator-(const bigint &A,ll B){
		static bigint ret; ret=A;
		static ll now;
		for(int i=0;B;++i){
			now=B-ret.a[i];
			if(now<=0) ret.a[i]=-now,B=0;
			else{
				if(now%M) ret.a[i]=M-now%M,B=now/M+1;
				else ret.a[i]=0,B=now/M;
			}
		}
		while(ret.len && !ret.a[ret.len-1]) --ret.len;
		return ret;
	}
	il void operator-=(bigint &A,const bigint &B){
		static ll now; now=0;
		for(int i=0;i<A.len;++i){
			now=now+A.a[i]-B.a[i];
			if(now>=0) A.a[i]=now,now=0;
			else A.a[i]=now+M,now=-1;
		}
		while(A.len && !A.a[A.len-1]) --A.len;
		return;
	}
	il bigint operator-(const bigint &A,const bigint &B){
		static bigint ret; ret=bigint();
		static ll now; now=0,ret.len=A.len;
		for(int i=0;i<A.len;++i){
			now=now+A.a[i]-B.a[i];
			if(now>=0) ret.a[i]=now,now=0;
			else ret.a[i]=now+M,now=-1;
		}
		while(ret.len && !ret.a[ret.len-1]) --ret.len;
		return ret;
	}
	
	il void operator*=(bigint &A,const ll B){
		static ll now; now=0;
		for(int i=0;i<A.len;++i){
			now=now+A.a[i]*B;
			A.a[i]=now%M,now/=M;
		}
		while(now) A.a[A.len]=now%M,++A.len,now/=M;
		return;
	}
	il bigint operator*(const bigint &A,const ll B){
		static bigint ret; ret=bigint();
		static ll now; now=0,ret.len=A.len;
		for(int i=0;i<A.len;++i){
			now=now+A.a[i]*B;
			ret.a[i]=now%M;
			now/=M; 
		}
		while(now) ret.a[ret.len]=now%M,++ret.len,now/=M;
		return ret;
	}
	il void operator*=(bigint &A,const bigint &B){
		static bigint ret; ret=bigint();
		static ll now; now=0,ret.len=mymin(A.len+B.len+1,uselen);
		for(int i=0;i<A.len;++i){
			for(int j=0;j<B.len;++j){
				now+=ret.a[i+j]+A.a[i]*B.a[j];
				ret.a[i+j]=now%M,now/=M;
			}
			for(int k=i+B.len;now;++k){
				now+=ret.a[k];
				ret.a[k]=now%M,now/=M;
			}
		}
		while(ret.len && !ret.a[ret.len-1]) --ret.len;
		A=ret; return;
	}
	il bigint operator*(const bigint &A,const bigint &B){
		static bigint ret; ret=bigint();
		static ll now; now=0,ret.len=mymin(A.len+B.len+1,uselen);
		for(int i=0;i<A.len;++i){
			for(int j=0;j<B.len;++j){
				now+=ret.a[i+j]+A.a[i]*B.a[j];
				ret.a[i+j]=now%M,now/=M;
			}
			for(int k=i+B.len;now;++k){
				now+=ret.a[k];
				ret.a[k]=now%M,now/=M;
			}
		}
		while(ret.len && !ret.a[ret.len-1]) --ret.len;
		return ret;
	}
	
	il void mul2(bigint &A){
		static ll now; now=0;
		for(int i=0;i<A.len;++i){
			now=now+(A.a[i]<<1);
			if(now<M) A.a[i]=now,now=0;
			else A.a[i]=now-M,now=1;
		}
		if(now) A.a[A.len]=now,++A.len;
		return;
	}
	
	il void operator/=(bigint &A,const ll B){
		static ll now,res; now=0;
		static bool flag; flag=1;
		for(int i=A.len-1;~i;--i){
			res=now+A.a[i];
			A.a[i]=res/B;
			if(flag){
				if(!A.a[i]) --A.len;
				else flag=0;
			}
			now=res%B*M;
		}
		return;
	}
	il pair<bigint,ll> operator/(const bigint &A,const ll B){
		static pair<bigint,ll> ret;
		static ll res;;
		static bool flag; flag=1;
		ret.fir=bigint(),ret.sec=0;
		for(int i=A.len-1;~i;--i){
			res=ret.sec+A.a[i];
			ret.fir.a[i]=res/B;
			if(flag && ret.fir.a[i]) ret.fir.len=i+1,flag=0;
			ret.sec=res%B*M;
		}
		return ret;
	}
	
	il void div2(bigint &A){
		static ll now,res; now=0;
		static bool flag; flag=1;
		for(int i=A.len-1;~i;--i){
			res=now+A.a[i];
			A.a[i]=res>>1;
			if(flag){
				if(!A.a[i]) --A.len;
				else flag=0;
			}
			now=(res&1)*M;
		}
		return;
	}
	il void div2(pair<bigint,ll> &A){
		static ll res; A.sec=0;
		static bool flag; flag=1;
		for(int i=A.fir.len-1;~i;--i){
			res=A.sec+A.fir.a[i];
			A.fir.a[i]=res>>1;
			if(flag){
				if(!A.fir.a[i]) --A.fir.len;
				else flag=0;
			}
			A.sec=(res&1)*M;
		}
		A.sec/=M; return;
	}
	il pair<bigint,ll> div2r(const bigint &A){
		static pair<bigint,ll> ret; 
		static ll res;
		static bool flag; flag=0;
		ret.fir=bigint(),ret.sec=0;
		for(int i=A.len-1;~i;--i){
			res=ret.sec+A.a[i];
			ret.fir.a[i]=res>>1;
			if(flag && ret.fir.a[i]) ret.fir.len=i+1,flag=0;
			ret.sec=(res&1)*M;
		}
		ret.sec/=M; return ret;
	}
	
	struct big2{
		string a;
		big2(){a.clear();}
		il char &operator[](int key){return a[key];}
		il void push_back(int x){a.p_b(x); return;}
		il size_t size(){return a.size();}
	};
	il big2 big2big2(const bigint &A){
		static big2 ret; ret=big2();
		static pair<bigint,ll> now; now.fir=A;
		while(!now.fir.empty()) div2(now),ret.p_b(now.sec);
		return ret;
	}
	
	il void big2wt(const big2 &A){
		for(char c:A.a) pc(c|48);
		return;
	}
	il void big2wtk(const big2 &A){big2wt(A),pc(' '); return;}
	il void big2wth(const big2 &A){big2wt(A),pc('\n'); return;}
}

  • \(M\) 为进制,\(uselen\) 为最大位数(实际上用的是第 \(0\sim uselen-1\) 位)。足够表示 \(10^{9uselen}-1\) 的数字。

  • 其中的读入和输出是基于 \(M=10^9\) 而实现的,若需要改变进制,请调整相关函数。

  • 其中的左右移为 \(M\) 进制意义下的。特别实现了一个取以十为底的对数的操作,注意这一操作取到的对数是对数的一个不紧的下界,实际的对数 \(\lg A\) 的区间为 \([A.lg,A.lg+\lg 2)\)

  • 从 div2 开始是一车乱七八糟的二进制特化,以及一个不成熟的 string 式二进制高精。

  • 因为设计上是打算直接 using namespace 的,所以命名空间的名称很长。

posted @ 2023-01-15 09:58  未欣  阅读(34)  评论(0编辑  收藏  举报