[zoj4058] [2018ACM青岛站·A] Sequence and Sequence - 高精度 - 数学

传送门:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5815&HPPROTID=f0b51c92

个人第一场ACM,虽然6题Ag滚粗但还是非常值得回味的。

虽然预料到会有高精度题,但是题目的疯狂程度还是超乎想象(当然没有队伍现场ac了)。

题目大意:定义p序列为{1,1,2,2,2,3,3,3,3……}即连续2个1,连续3个2,连续4个3……,再定义q序列为:

q1 = 1,q(n) = q(n - 1) + q(pi)

t(约1e4)组询问,给定n(<=1e40),求q(n)。

看到巨大的n,显然的想法是如何将其变成一个可以接受的范围。

第一步还是比较容易想到的:

q(n)=sigma i=1~n q(pi)

然后将q(pi)用同样的方式展开:

sigma i=1~n sigma j=1~pi q(pj)

分析p序列的性质,发现pi=最大的j使得j*(j+1)/2<=i。

所以,对于某一个q(pj),会在i=j*(j+1)/2~n被计算贡献

sigma j=1~pn q(pj) * (n - (j*(j+1)/2 - 1))

=n*sigma j=1~pn q(pj) - sigma j=1~pn q(pj)*(j*(j+1)/2-1)

到这一步为止,我们成功地把1~n变成了1~pn。

由于pn是O(sqrtn)级别,看起来只需要不停地递归迭代下去,迭代4次就能变成几百左右(实际上p(p(p(pn)))=605)。

但这就结束了吗?

观察上式,我们发现第一部分确实是可以直接递归的,然而第二部分的每一项还需要乘一个跟j有关的多项式。

怎么办?不急,我们继续推式子。

假设我们要求的是sigma i=1~n q(pi)*f(i),其中f(i)是某个多项式。

仍然沿用之前的推法,我们能够得到:

记sn = sigma i=1~n fi为f的前缀和。

sn * sigma i=1~pn q(pi) - sigma i=1~pn q(pi)*s(i*(i+1)/2-1)

这个式子与之前的式子形式很类似。实际上,如果把之前的式子看做是q(pi)*1的话,两者是相同的。

所以我们可以进行如下操作:

定义f(0,n)=1,f(i,n)=s(i-1,n*(n+1)/2-1),s(i,n)=sigma j=1~n f(j,i)

再定义ans(i,n)=sigma j=1~pn q(pj)*f(i,j),则ans(0,n)即为所求

且ans(i,n)=s(i,n)*ans(0,pn) - ans(i+1,pn)

我们只需要用插值等方法把i=0~3时的f(i,n)和s(i,n)算出来(直接保留多项式的形式,以便计算s(i,n)),再对j=1~605预处理出ans(i,j),然后每次询问时递归下去即可。

还有一些常数优化技巧,比如可以事先打出多项式的系数然后直接在程序里打表(这样多项式的系数可以直接开ll),以及每次预处理出所有可能用到的pn和s(i,n)值等。

当然写起来巨麻烦无比,需要手写高精度和多项式类,两者需要实现的东西也很多,因此诞生了我有史以来的第一个1000+行的程序!

#include
using namespace std;
#define gc getchar()
#define pc putchar
#define li long long
inline li ll_in(){
	li x = 0,y = 0,c = getchar();
	while(!isdigit(c)) y = c,c = getchar();
	while(c >= '0' && c <= '9') x = (x << 1) + (x << 3) + (c ^ '0'),c = getchar();
	return y == '-' ? -x : x;
}
inline void ll_out(li q){
	if(q < 0){
		putchar('-');
		q = -q;
	} 
	if(q >= 10) ll_out(q / 10);
	putchar(q % 10 + '0');
}

/*****************************以下为高精度***************************/
const li MAX_PER_UNIT = 100000000;
struct gjd{
	vector
  • a;//存储高精度数据 int len;//该数据的位数 bool fh;//符号,0为非负1为负 gjd(){//初始化(清零) len = fh = 0;a.clear(); } inline gjd operator = (li x){ a.clear();len = fh = 0; if(x < 0){ fh = 1;x = -x; } while(x){ a.push_back(x % MAX_PER_UNIT); x /= MAX_PER_UNIT; } len = a.size(); return *this; } inline gjd operator = (string c){ a.clear();len = fh = 0; if(c.size() == 1 && c[0] == '0') return *this; int q = MAX_PER_UNIT,j = 0,d = 0; while(j < c.size() && (c[j] < '0' || c[j] > '9')) d = c[j++]; while(j < c.size() && c[j] == '0') ++j; if(j == c.size()) return *this; for(int i = c.size() - 1;i >= j;--i){ if(q == MAX_PER_UNIT){ a.push_back(c[i] - '0'); ++len; q = 10; } else{ a[len - 1] += (c[i] - '0') * q; q *= 10; } } if(len && d == '-') fh = 1; return *this; } inline gjd operator = (char *c){ a.clear();len = fh = 0; int tp = strlen(c); if(tp == 1 && c[0] == '0') return *this; int q = MAX_PER_UNIT,j = 0,d = 0; while(j < tp && (c[j] < '0' || c[j] > '9')) d = c[j++]; while(j < tp && c[j] == '0') ++j; if(j == tp) return *this; for(int i = tp - 1;i >= j;--i){ if(q == MAX_PER_UNIT){ a.push_back(c[i] - '0'); ++len; q = 10; } else{ a[len - 1] += (c[i] - '0') * q; q *= 10; } } if(len && d == '-') fh = 1; return *this; } inline void read(){//读入 a.clear();len = fh = 0; vector c; char d,e = 0; int i = 0; d = getchar(); while(d < '0' || d > '9') e = d,d = getchar();//屏蔽非数字字符 while(d == '0') d = getchar();//屏蔽前导0 if(d == -1) return;//处理读入0 while(d >= '0' && d <= '9') ++i,c.push_back(d),d = getchar(); int q = MAX_PER_UNIT; for(--i;i >= 0;--i){ if(q == MAX_PER_UNIT){ a.push_back(c[i] - '0'); ++len; q = 10; } else{ a[len - 1] += (c[i] - '0') * q; q *= 10; } } if(len && e == '-') fh = 1; } inline void print(){//输出 int i = len; if(i == 0){ putchar('0'); return; } if(fh) putchar('-'); ll_out(a[i - 1]); for(i -= 2;i >= 0;--i){ if(a[i] < 10000000) putchar('0'); if(a[i] < 1000000) putchar('0'); if(a[i] < 100000) putchar('0'); if(a[i] < 10000) putchar('0'); if(a[i] < 1000) putchar('0'); if(a[i] < 100) putchar('0'); if(a[i] < 10) putchar('0'); ll_out(a[i]); } } }; inline void clear(gjd &x){//初始化(清零) x.a.clear(); x.len = 0; } inline gjd turn(li x){//将低精转化为高精 gjd y; if(x < 0){ y.fh = 1;x = -x; } while(x){ y.a.push_back(x % MAX_PER_UNIT); x /= MAX_PER_UNIT; } y.len = y.a.size(); return y; } inline li turn(gjd z){//将高精转化为低精(有爆ll风险,慎用) li x = 0; for(int i = z.len - 1;i >= 0;--i) x = x * MAX_PER_UNIT + z.a[i]; return z.fh ? -x : x; } inline void swap(gjd &x,gjd &y){//交换两个高精度数据 gjd t = x; x = y; y = t; } inline gjd abs(gjd x){//高精度数据取绝对值 x.fh = 0; return x; } inline gjd operator - (gjd x){//相反数 if(x.len) x.fh ^= 1; return x; } inline int cmp(gjd x,gjd y){//高精与高精比较大小 if(x.fh && !y.fh) return -1; if(!x.fh && y.fh) return 1; int tmp = 1; if(x.fh && y.fh) tmp = -1; int q = x.len,w = y.len; if(q > w) return tmp; if(w > q) return -tmp; for(--q;q >= 0;--q){ if(x.a[q] > y.a[q]) return tmp; if(x.a[q] < y.a[q]) return -tmp; } return 0; } inline bool operator == (gjd b,gjd c){ return cmp(b,c) == 0; } inline bool operator < (gjd b,gjd c){ return cmp(b,c) == -1; } inline bool operator > (gjd b,gjd c){ return cmp(b,c) == 1; } inline bool operator <= (gjd b,gjd c){ return cmp(b,c) != 1; } inline bool operator >= (gjd b,gjd c){ return cmp(b,c) != -1; } inline bool operator != (gjd b,gjd c){ return cmp(b,c) != 0; } inline int cmp(gjd x,li b){//高精与低精比较大小 return cmp(x,turn(b)); } inline bool operator == (gjd b,li c){ return cmp(b,c) == 0; } inline bool operator < (gjd b,li c){ return cmp(b,c) == -1; } inline bool operator > (gjd b,li c){ return cmp(b,c) == 1; } inline bool operator <= (gjd b,li c){ return cmp(b,c) != 1; } inline bool operator >= (gjd b,li c){ return cmp(b,c) != -1; } inline bool operator != (gjd b,li c){ return cmp(b,c) != 0; } inline int cmp(li b,gjd c){//低精与高精比较大小 return cmp(c,b); } inline bool operator == (li b,gjd c){ return cmp(b,c) == 0; } inline bool operator < (li b,gjd c){ return cmp(b,c) == -1; } inline bool operator > (li b,gjd c){ return cmp(b,c) == 1; } inline bool operator <= (li b,gjd c){ return cmp(b,c) != 1; } inline bool operator >= (li b,gjd c){ return cmp(b,c) != -1; } inline bool operator != (li b,gjd c){ return cmp(b,c) != 0; } inline gjd max(gjd x,gjd y){//高精与高精取最大值 return x > y ? x : y; } inline gjd max(gjd x,li y){//高精与低精取最大值 return x >= y ? x : turn(y); } inline gjd max(li x,gjd y){//低精与高精取最大值 return x > y ? turn(x) : y; } inline gjd min(gjd x,gjd y){//高精与高精取最小值 return x < y ? x : y; } inline gjd min(gjd x,li y){//高精与低精取最小值 return x <= y ? x : turn(y); } inline gjd min(li x,gjd y){//低精与高精取最小值 return x < y ? turn(x) : y; } inline gjd jia(gjd b,gjd c) {//高精加高精的绝对值相加,要求b,c>=0 if(c.len == 0) return b; if(b.len == 0) return c; int z = 0; gjd d; int l1 = b.len,l2 = c.len,t1,t2; d.a.resize(max(l1,l2) + 1); while(z < l1 || z < l2){ if(l1 > z) t1 = b.a[z]; else t1 = 0; if(l2 > z) t2 = c.a[z]; else t2 = 0; d.a[z] += t1 + t2; if(d.a[z] >= MAX_PER_UNIT) d.a[z + 1] = 1,d.a[z] -= MAX_PER_UNIT; ++z; } d.len = d.a.size(); while(d.len && !d.a[d.len - 1]) --d.len; return d; } inline gjd jia(gjd b,li c){//高精加低精的绝对值相加,要求b,c>=0 if(c == 0) return b; if(b.len == 0) return turn(c); if(c > 9000000000000000000ll) return jia(b,turn(c));//不然会爆ll int z = 0; b.a[0] += c; while(b.a[z] >= MAX_PER_UNIT){ if(b.a.size() == z + 1) b.a.push_back(b.a[z] / MAX_PER_UNIT); else b.a[z + 1] += b.a[z] / MAX_PER_UNIT; b.a[z] %= MAX_PER_UNIT; ++z; } b.len = max(b.len,z + 1); return b; } inline gjd jian(gjd z,li x){//高精减低精的绝对值相减,要求z>=x>=0 if(x == 0) return z; int q = 0,w = -1; z.a[0] -= x; while(z.a[q] < 0){ z.a[q + 1] += z.a[q] / MAX_PER_UNIT; z.a[q] %= MAX_PER_UNIT; if(z.a[q] < 0){ z.a[q] += MAX_PER_UNIT; --z.a[q + 1]; } if(z.a[q]) w = q; ++q; } if(z.len == q + 1 && z.a[q] == 0) z.len = w + 1; return z; } inline gjd jian(gjd b,gjd c){//高精减高精的绝对值相减,要求b>=c>=0 if(c.len == 0) return b; int z = 0,w = -1; int l1 = b.len,l2 = c.len; gjd d; d.a.resize(b.len); int tp; while(z < l1){ if(l2 > z) tp = c.a[z]; else tp = 0; d.a[z] += b.a[z] - tp; if(d.a[z] < 0){ d.a[z] += MAX_PER_UNIT; d.a[z + 1] = -1; } if(d.a[z]) w = z; ++z; } d.len = w + 1; return d; } inline gjd operator + (gjd z,li x){//高精加低精 if(!z.fh && x >= 0) return jia(z,x); gjd a; if(z.fh && x < 0){ z.fh = 0;x = -x; a = jia(z,x); a.fh = 1; return a; } if(!z.fh && x < 0){ x = -x; if(z >= x){ a = jian(z,x); a.fh = 0; } else{ a = jian(turn(x),z); a.fh = 1; } return a; } if(z.fh && x >= 0){ z.fh = 0; if(z > x){ a = jian(z,x); a.fh = 1; } else{ a = jian(turn(x),z); a.fh = 0; } return a; } return a; } inline gjd operator + (gjd z,gjd x){//高精加高精 if(!z.fh && !x.fh) return jia(z,x); if(z > x) swap(z,x); gjd a; if(z.fh && x.fh){ z.fh = x.fh = 0; a = jia(z,x); a.fh = 1; return a; } if(z.fh && !x.fh){ z.fh = 0; if(z > x){ a = jian(z,x); a.fh = 1; } else{ a = jian(x,z); a.fh = 0; } return a; } return a; } inline gjd operator + (li z,gjd x){//低精加高精 return x + z; } inline gjd operator += (gjd &z,li x){ z = z + x; return z; } inline gjd operator += (gjd &z,gjd x){ z = z + x; return z; } inline li operator += (li &z,gjd x){//请注意爆long long风险 z = z + turn(x); return z; } inline gjd operator ++ (gjd &z){//由于特殊原因,使用时只能写作++z,不能写作z++ z = z + 1; return z; } inline gjd operator - (gjd z,li x){//高精减低精 return z + (-x); } inline gjd operator - (gjd z,gjd x){//高精减高精 if(x.len) x.fh ^= 1; return z + x; } inline gjd operator - (li b,gjd c){//低精减高精 return turn(b) - c; } inline gjd operator -= (gjd &z,li x){ z = z - x; return z; } inline gjd operator -= (gjd &z,gjd x){ z = z - x; return z; } inline li operator -= (li &z,gjd x){//请注意爆long long风险 z = z - turn(x); return z; } inline gjd operator -- (gjd &z){//由于特殊原因,使用时只能写作--z,不能写作z-- z = z - 1; return z; } inline gjd operator * (gjd,gjd); inline gjd operator * (gjd b,li c){//高精乘低精 if(b.len == 0 || c == 0) return turn(0); if(c > 10000000000ll) return b * turn(c);//不然会爆long long int l = b.len,i,j; j = b.fh ^ (c < 0); b.fh = 0;c = abs(c); for(i = 0;i < l;++i) b.a[i] *= c; for(i = 0;i < l - 1;++i){ b.a[i + 1] += b.a[i] / MAX_PER_UNIT; b.a[i] %= MAX_PER_UNIT; } while(b.a[i] >= MAX_PER_UNIT){ if(b.a.size() == i + 1) b.a.push_back(b.a[i] / MAX_PER_UNIT); else b.a[i + 1] = b.a[i] / MAX_PER_UNIT; b.a[i] %= MAX_PER_UNIT; ++i; } b.len = i + 1; b.fh = j; return b; } inline gjd operator * (gjd b,gjd c){//高精乘高精 if(b.len == 0 || c.len == 0) return turn(0); if(min(b.len,c.len) <= 200){ gjd d; d.fh = b.fh ^ c.fh; b.fh = c.fh = 0; int i,j; int l1 = b.len,l2 = c.len; d.a.resize(l1 + l2 - 1); for(i = 0;i < l1;++i){ for(j = 0;j < l2;++j){ d.a[i + j] += b.a[i] * c.a[j]; } } for(i = 0;i < l1 + l2 - 2;++i){ d.a[i + 1] += d.a[i] / MAX_PER_UNIT; d.a[i] %= MAX_PER_UNIT; } while(d.a[i] >= MAX_PER_UNIT){ if(d.a.size() == i + 1) d.a.push_back(d.a[i] / MAX_PER_UNIT); else d.a[i + 1] = d.a[i] / MAX_PER_UNIT; d.a[i] %= MAX_PER_UNIT; ++i; } d.len = i + 1; return d; } int l = max(b.len,c.len) / 2; gjd ans,b1,b2,c1,c2,s1,s2,s3,s4,s5; int tmp = b.fh ^ c.fh; b.fh = c.fh = 0; int i; b1.len = min(l,b.len); b1.a.resize(b1.len); for(i = 0;i < l && i < b.len;++i) b1.a[i] = b.a[i]; c1.len = min(l,c.len); c1.a.resize(c1.len); for(i = 0;i < l && i < c.len;++i) c1.a[i] = c.a[i]; if(b.len > l){ b2.a.resize(b.len - 1); for(i = l;i < b.len;++i) b2.a[i - l] = b.a[i]; b2.len = b.len - l; } if(c.len > l){ c2.a.resize(c.len - 1); for(i = l;i < c.len;++i) c2.a[i - l] = c.a[i]; c2.len = c.len - l; } while(b1.len && !b1.a[b1.len - 1]) --b1.len; while(c1.len && !c1.a[c1.len - 1]) --c1.len; while(b2.len && !b2.a[b2.len - 1]) --b2.len; while(c2.len && !c2.a[c2.len - 1]) --c2.len; s1 = b1 * c1; s2 = b2 * c2; s3 = (b1 + b2) * (c1 + c2) - s1 - s2; if(s2.len){ s4.a.resize((l << 1) + s2.len); for(i = 0;i < s2.len;++i) s4.a[i + (l << 1)] = s2.a[i]; s4.len = (l << 1) + s2.len; } if(s3.len){ s5.a.resize(l + s3.len); for(i = 0;i < s3.len;++i) s5.a[i + l] = s3.a[i]; s5.len = l + s3.len; } ans = s1 + s4 + s5;ans.fh = tmp; return ans; } inline gjd operator * (li z,gjd x){//低精乘高精 return x * z; } inline gjd operator *= (gjd &z,li x){ z = z * x; return z; } inline gjd operator *= (gjd &z,gjd x){ z = z * x; return z; } inline li operator *= (li &z,gjd x){//请注意爆long long风险 z = z * turn(x); return z; } inline gjd operator / (gjd b,li c){//高精除以低精 if(!c){ puts("error:divided by zero!"); exit(1); } if(b.len == 0) return turn(0); gjd q; q.fh = b.fh ^ (c < 0); b.fh = 0;c = abs(c); int l = b.len - 1; int x = 0,y; while(l){ y = b.a[l] / c; if(!x && y){ x = l; q.a.resize(x); q.a.push_back(y); } if(x) q.a[l] = y; b.a[l - 1] += b.a[l] % c * MAX_PER_UNIT; --l; } if(!x){ y = b.a[0] / c; if(!y) return q; q.a.push_back(y); q.len = x + 1; return q; } q.a[0] = b.a[0] / c; if(!q.a[0] && !x) q.len = 0; else q.len = x + 1; return q; } inline gjd operator / (gjd b,gjd c){//高精除以高精 if(c.len == 0){ puts("error:divided by zero!"); exit(1); } if(b.len == 0) return turn(0); int tmp = b.fh ^ c.fh; b.fh = c.fh = 0; if(b < c) return turn(0); gjd q,w;//q:商;w:余数 int i = b.len - 1,l = -1,al,ar,am; for(;i >= 0;i--){ w = w * MAX_PER_UNIT + b.a[i]; if(w >= c){ if(l == -1) q.a.resize(i + 1); l = max(l,i); al = 1,ar = MAX_PER_UNIT - 1; while(al <= ar){ am = al + ar >> 1; if(w >= c * am){ q.a[i] = am; al = am + 1; } else ar = am - 1; } w -= c * q.a[i]; } } q.len = l + 1; q.fh = tmp; return q; } inline gjd operator / (li x,gjd y){//低精除以高精 return turn(x) / y; } inline gjd operator /= (gjd &z,li x){ z = z / x; return z; } inline gjd operator /= (gjd &z,gjd x){ z = z / x; return z; } inline li operator /= (li &z,gjd x){//请注意爆long long风险 if(z < x){ z = 0; return z; } z = z / turn(x); return z; } inline gjd operator % (gjd b,li c){//高精模低精 if(!c){ puts("error:divided by zero!"); exit(1); } if(b.len == 0) return turn(0); int l = b.len - 1,tmp = b.fh; b.fh = 0;c = abs(c); while(l){ b.a[l - 1] += b.a[l] % c * MAX_PER_UNIT; --l; } b.a[0] %= c; gjd y = turn(b.a[0]); y.fh = tmp; return y; } inline gjd operator % (gjd b,gjd c){//高精模高精 if(c.len == 0){ puts("error:divided by zero!"); exit(1); } if(b.len == 0) return turn(0); gjd w,tp;//w:余数 tp:辅助计算 int tmp = b.fh; b.fh = c.fh = 0; if(b < c){ b.fh = tmp; return b; } int i = b.len - 1,j; for(;i >= 0;--i){ w = w * MAX_PER_UNIT + b.a[i]; j = 1 << 26; while(j){ tp = c * j; if(w >= tp) w -= tp; j >>= 1; } } w.fh = tmp; return w; } inline gjd operator % (li x,gjd y){//低精模高精 return turn(x) % y; } inline gjd operator %= (gjd &z,li x){ z = z % x; return z; } inline gjd operator %= (gjd &z,gjd x){ z = z % x; return z; } inline li operator %= (li &z,gjd x) {//请注意爆long long风险 if(z < x) return z; z = z % turn(x); return z; } inline gjd spw(gjd q,li w){//高精度数据的单精度次幂运算,结果为高精度,要求指数是非负整数 if(w < 0){ puts("error:in function 'spw(gjd q,long long int w)',w is negative!"); exit(1); } if(!w) return turn(1); if(w == 1) return q; gjd z; z = spw(q,w >> 1); z = z * z; if(w & 1) z = z * q; return z; } inline gjd spw(li q,li w){//两个单精度数据的幂运算,结果为高精度,要求指数是非负整数 return spw(turn(q),w); } inline gjd operator ^ (gjd q,li w){ return spw(q,w); } inline gjd operator ^= (gjd &q,li w){ q = q ^ w; return q; } //以下为指数是高精度的幂运算,小心结果可能很大! inline gjd spw(gjd q,gjd w){ return spw(q,turn(w)); } inline gjd spw(li q,gjd w){ return spw(turn(q),turn(w)); } inline gjd operator ^ (gjd q,gjd w){ return spw(q,turn(w)); } inline gjd operator ^= (gjd &q,gjd w){ q = q ^ w; return q; } inline gjd operator ^ (li q,gjd w){ return spw(turn(q),turn(w)); } inline li operator ^= (li &q,gjd w){//小心爆ll的风险 q = turn(q ^ w); return q; } inline gjd sqrt(gjd b){//高精开平方(牛顿迭代法) if(b.fh){ puts("error:in function 'sqrt(gjd b)',b is negative!"); exit(1); } if(b.len == 0) return turn(0); gjd z[2],tmp; bool i = 0; z[1].a.resize((b.len + 1) / 2 - 1); z[1].a.push_back(1); z[1].len = (b.len + 1) / 2; while(z[i] != z[!i]){ tmp = (b / z[!i] + z[!i]) / 2; if(z[!i] > z[i] && z[!i] - z[i] == 1 && z[i] == tmp) break; z[i] = tmp; i = !i; } return z[i]; } inline gjd sqr(gjd a,li b){//二分法高精开b次方根,要求次数为正整数 if(b <= 0){ puts("error:in function 'sqr(gjd a,li b)',b is not positive!"); exit(1); } if(a.fh && b % 2 == 0){ puts("error:in function 'sqr(gjd a,li b)',a is negative and b is even!"); exit(1); } if(a.len == 0) return turn(0); if(b == 1) return a; int tmp = a.fh; a.fh = 0; if(a <= b) return turn(1 * tmp); gjd l,r,mid,ans; l.a.resize((a.len - 1) / b);r.a.resize((a.len - 1) / b + 1); l.a.push_back(1);l.len = (a.len - 1) / b + 1;r.a.push_back(1);r.len = l.len + 1; if(b == 2){ while(l <= r){ mid = (l + r) / 2; if(mid * mid <= a){ ans = mid; l = mid + 1; } else r = mid - 1; } } else{ while(l <= r){ mid = (l + r) / 2; if(spw(mid,b) <= a){ ans = mid; l = mid + 1; } else r = mid - 1; } } ans.fh = tmp; return ans; } inline gjd gcd(gjd x,gjd y){//高精度与高精度的最大公因数,返回值非负(下同) x.fh = y.fh = 0; if(!x.len) return y; if(!y.len) return x; gjd q = turn(1); if(x < y) swap(x,y); while(x != y){ if((x.a[0] & 1) && (y.a[0] & 1)) x -= y; else if(x.a[0] & 1) y /= 2; else if(y.a[0] & 1) x /= 2; else{ x /= 2; y /= 2; q *= 2; } if(x < y) swap(x,y); } return q * x; } inline gjd gcd(gjd x,li y){//高精度与单精度的最大公因数 x.fh = 0;y = abs(y); return y == 0 ? x : gcd(turn(y),x % y); } inline gjd gcd(li x,gjd y){//单精度与高精度的最大公因数 return gcd(y,x); } inline gjd gjd_gcd(li x,li y){//单精度与单精度的最大公因数,结果返回高精 x = abs(x);y = abs(y); return y == 0 ? turn(x) : gjd_gcd(y,x % y); } inline li gcd(li x,li y){//单精度与单精度的最大公因数,结果返回单精 x = abs(x);y = abs(y); return y == 0 ? x : gcd(y,x % y); } inline gjd lcm(gjd x,gjd y){//高精度与高精度的最小公倍数 x.fh = y.fh = 0; if(!x.len || !y.len) return turn(0); return x / gcd(x,y) * y; } inline gjd lcm(gjd x,li y){//高精度与单精度的最小公倍数 x.fh = 0;y = abs(y); if(!x.len || !y) return turn(0); return x / gcd(x,y) * y; } inline gjd lcm(li x,gjd y){//单精度与高精度的最小公倍数 return lcm(y,x); } inline gjd gjd_lcm(li x,li y){//单精度与单精度的最小公倍数,结果返回高精 x = abs(x);y = abs(y); if(!x || !y) return turn(0); return x / gjd_gcd(x,y) * y; } inline li lcm(li x,li y){//单精度与单精度的最小公倍数,结果返回单精 x = abs(x);y = abs(y); if(!x || !y) return 0; return x / gcd(x,y) * y; } /*****************************以上为高精度***************************/ /*****************************以下为多项式***************************/ const int sz = 17; struct dxs{ gjd a[sz]; gjd div; int len; dxs(){ for(int i = 0;i < sz;++i) clear(a[i]); div = 1;len = 0; } void clr(){ for(int i = 0;i < sz;++i) clear(a[i]); div = 1;len = 0; } void out(){ ll_out(len);pc('\n'); for(int i = 0;i <= len;++i){ a[i].print();pc(' '); } pc('\n');div.print();pc('\n'); } }a[6],s[6]; void yf(dxs &q){ if(q.div.fh){ q.div.fh ^= 1; for(int i = 0;i <= q.len;++i) if(q.a[i].len) q.a[i].fh ^= 1; } gjd g = q.div; for(int i = 0;i <= q.len;++i) g = gcd(g,q.a[i]); q.div /= g; for(int i = 0;i <= q.len;++i) q.a[i] /= g; while(q.len && q.a[q.len] == 0) --q.len; } dxs operator + (dxs q,dxs w){ gjd a = lcm(q.div,w.div); gjd b = a / q.div,c = a / w.div; dxs ans; ans.len = max(q.len,w.len); ans.div = a; for(int i = 0;i <= ans.len;++i) ans.a[i] = q.a[i] * b + w.a[i] * c; yf(ans); return ans; } dxs operator * (dxs q,dxs w){ dxs ans; ans.len = q.len + w.len; ans.div = q.div * w.div; for(int i = 0;i <= q.len;++i){ for(int j = 0;j <= w.len;++j){ ans.a[i + j] += q.a[i] * w.a[j]; } } yf(ans); return ans; } /*****************************以上为多项式***************************/ /*****************************以下为预处理部分***************************/ gjd tmp[10010],val[1010][6]; int p1[1010]; inline gjd getp(gjd q){ gjd ans = sqr(q * 2,2); if((ans + 1) * ans > q * 2) --ans; return ans; } inline gjd getx(dxs q,gjd x){ gjd ans = q.a[q.len]; for(int i = q.len - 1;i >= 0;--i) ans = ans * x + q.a[i]; return ans / q.div; } dxs tp2[35]; dxs cheng(int l,int r){ if(l == r) return tp2[l]; int mid = l + r >> 1; return cheng(l,mid) * cheng(mid + 1,r); } inline void wk(dxs q,dxs &w,bool fg,int mx){ int i,j = 1; for(i = 1;i <= mx;++i){ tmp[i] = tmp[i - 1]; for(;j <= (!fg ? i * (i + 1) / 2 - 1 : i);++j) tmp[i] += getx(q,turn(j)); } w.clr(); for(i = 1;i <= mx;++i){ dxs tp; gjd tp3;tp3 = 1; tp.a[0] = 1; for(j = 1;j <= mx;++j) if(i != j){ tp2[j].a[1] = 1;tp2[j].a[0] = -j;tp2[j].len = 1; tp3 *= i - j; } tp2[i].clr();tp2[i].a[0] = 1; tp = cheng(1,mx); tp.div = tp3; for(j = 0;j <= tp.len;++j) tp.a[j] *= tmp[i]; yf(tp); w = w + tp; } } const int mx = 605; void init(){ register int i,j; p1[1] = 1; for(i = 2;i <= mx;++i) p1[i] = turn(getp(turn(i))); a[0].a[0] = 1; s[0].a[1] = 1; s[0].len = 1; val[1][0] = 1; for(i = 2;i <= mx;++i) val[i][0] = val[i - 1][0] + val[p1[i]][0]; for(i = 1;i <= 3;++i){ wk(a[i - 1],a[i],0,pow(2,i + 1) - 1); wk(a[i],s[i],1,pow(2,i + 1)); val[1][i] = getx(a[i],turn(1)); for(j = 2;j <= mx;++j) val[j][i] = val[j - 1][i] + val[p1[j]][0] * getx(a[i],turn(j)); } //for(i = 0;i <= 3;++i) a[i].out(); //for(i = 0;i <= 3;++i) s[i].out(); for(i = 1;i <= mx;++i) val[i][4] = val[i - 1][4] + val[p1[i]][0] * getx(s[3],turn(i * (i + 1) / 2 - 1)); } /*****************************以上为预处理部分***************************/ gjd pp[6],ss[6][6]; gjd work(int q,int k){ if(pp[q] <= mx) return val[turn(pp[q])][k]; return ss[q][k] * work(q + 1,0) - work(q + 1,k + 1); } inline void file(){ freopen("a.in","r",stdin); freopen("a.out","w",stdout); } int main(){ //file(); init(); int t = ll_in(); while(t--){ pp[0].read(); ss[0][0] = pp[0]; for(int i = 1;i <= 4;++i){ pp[i] = getp(pp[i - 1]); if(i != 4){ ss[i][0] = pp[i]; for(int j = 1;j <= i;++j) ss[i][j] = getx(s[j],pp[i]); } } work(0,0).print(); pc('\n'); } return 0; }
  •  

    你可能感兴趣的:(杂题,重工业)