2022.10.3 模拟赛

T1 frame

  还是那个老 t r i c k trick trick 每个数取 log ⁡ \log log 乘法变加法,虽然最后还是要打一个高精。

// 高精的板子
struct Tnum{
	#define MAX_LEN 30030
	int len, isnagetive;
	int num[MAX_LEN];
	Tnum() { isnagetive = 0, len = 0; memset(num, 0, sizeof num); }
	void get(){
		string temp; cin >> temp;
		if(temp[0] == '-'){
			isnagetive = 1, len = temp.size() - 1;
			for(int i = 1; i <= len; i++) num[i] = temp[i] - '0';
		} else{
			len = temp.size();
			for(int i = 1; i <= len; i++) num[i] = temp[i - 1] - '0';
		}
	}
	Tnum add(Tnum a, Tnum b) {
		Tnum ans;
		ans.len = max(a.len, b.len);
		for(int i = 1; i <= ans.len; i++){
			int temp = a.num[len - i + 1] + b.num[b.len - i + 1];
			ans.num[i] += temp, temp = ans.num[i], ans.num[i] %= 10, ans.num[i + 1] += temp / 10 % 10;
		}
		if(ans.num[ans.len + 1]) ans.len++;
		reverse(ans.num + 1, ans.num + ans.len + 1);
		return ans;
	}
	Tnum minus(Tnum a, Tnum b){
		Tnum ans; ans.len = max(a.len, b.len);
		for(int i = 1; i <= ans.len; i++){
			int temp = 10 + a.num[a.len - i + 1] - b.num[max(0, b.len - i + 1)];
			ans.num[i] = temp % 10, a.num[a.len - i] += temp / 10 - 1;
		}
		while(ans.len > 1 and !ans.num[ans.len]) ans.len--;
		reverse(ans.num + 1, ans.num + ans.len + 1);
		return ans;
	}
	Tnum mul(Tnum a, Tnum b){
		Tnum ans; ans.len = a.len + b.len;
		for(int i = 1; i <= a.len; i++){
			int temp = 0;
			for(int j = 1; j <= b.len; j++){
				temp += a.num[len - i + 1] * b.num[b.len - j + 1] + ans.num[i + j - 1];
				ans.num[i + j - 1] = temp % 10, temp /= 10;
			}
			ans.num[i + b.len] += temp;
		}
		while(ans.len > 1 and !ans.num[ans.len]) ans.len--;
		reverse(ans.num + 1, ans.num + ans.len + 1);
		return ans;
	}
	Tnum abs(Tnum a) { a.isnagetive = 0; return a; }
	bool operator == (const Tnum rhs) const {
		if(len != rhs.len) return false;
		if(isnagetive != rhs.isnagetive) return false;
		for(int i = 1; i <= len; i++) if(num[i] != rhs.num[i]) return false;
		return true;
	}
	bool operator < (const Tnum rhs) const {
		if(!isnagetive and !rhs.isnagetive){
			if(len == rhs.len){
				for(int i = 1; i <= len; i++)
					if(num[i] != rhs.num[i]) return num[i] < rhs.num[i];
			} else return len < rhs.len;
		}
		else if(isnagetive and rhs.isnagetive){
			if(len == rhs.len){
				for(int i = 1; i <= len; i++)
					if(num[i] != rhs.num[i]) return num[i] > rhs.num[i];
			} else return len > rhs.len;
		}
		else return isnagetive ? true : false;
	}
	bool operator > (const Tnum rhs) const {
		if(!isnagetive and !rhs.isnagetive){
			if(len == rhs.len){
				for(int i = 1; i <= len; i++)
					if(num[i] != rhs.num[i]) return num[i] > rhs.num[i];
			} else return len > rhs.len;
		}
		else if(isnagetive and rhs.isnagetive){
			if(len == rhs.len){
				for(int i = 1; i <= len; i++)
					if(num[i] != rhs.num[i]) return num[i] < rhs.num[i];
			} else return len < rhs.len;
		}
		else return isnagetive ? false : true;
	}
	bool operator <= (const Tnum rhs) const { return !(*this > rhs); }
	bool operator >= (const Tnum rhs) const { return !(*this < rhs); }
	Tnum operator + (Tnum rhs){
		Tnum ans;
		if(isnagetive and rhs.isnagetive) { ans = add(*this, rhs), ans.isnagetive = 1; return ans; } 
		if(!isnagetive and !rhs.isnagetive) { ans = add(*this, rhs), ans.isnagetive = 0; return ans; }
		if(!isnagetive and rhs.isnagetive){
			if(*this > abs(rhs)) ans = minus(*this, rhs);
			else ans = minus(rhs, *this), ans.isnagetive = 1;
			return ans;
		}
		if(isnagetive and !rhs.isnagetive){ 
			if(abs(*this) < rhs) ans = minus(rhs, *this);
			else ans = minus(*this, rhs), ans.isnagetive = 1;
			return ans;
		}
	}
	Tnum operator - (Tnum rhs){
		rhs.isnagetive ^= 1;
		Tnum ans = *this + rhs;
		rhs.isnagetive ^= 1;
		return ans;
	}
	Tnum operator * (Tnum rhs){
		Tnum ans;
		if(isnagetive == rhs.isnagetive) { ans = mul(*this, rhs); return ans; }
		else { ans = mul(*this, rhs), ans.isnagetive = 1; return ans; }
	}
	void operator += (Tnum rhs) { *this = *this + rhs; }
	void operator -= (Tnum rhs) { *this = *this - rhs; }
	void operator *= (Tnum rhs) { *this = *this * rhs; }
	void print() { if(num[1] and isnagetive) putchar('-'); for(int i = 1; i <= len; i++) cout << num[i]; puts(""); }
	#undef MAX_LEN
};

Tnum to(int x){
	Tnum ans;
	ans.len = log(x) / log(10) + 1;
	int pos = 1;
	while(x) ans.num[ans.len - pos + 1] = x % 10, x /= 10, pos++;
	return ans;
}

59 pts

  直接暴力就是 O ( n 4 ) O(n^4) O(n4) ,最后记一下位置然后输出就完了:

namespace sub1{
	double s[MAXN][MAXN] = { 0 };
	double vv[MAXN][MAXN] = { 0 };
	inline double cal(int x, int y, int a, int b) { return s[a][b] - s[x - 1][b] + s[x - 1][y - 1] - s[a][y - 1]; }
	void solve(){
		double ans = 0; int ax, ay, aa, ab;
		for(int i = 1; i <= n; i++)
			for(int j = 1; j <= m; j++) vv[i][j] = log(v[i][j]);
		for(int i = 1; i <= n; i++)
			for(int j = 1; j <= m; j++)
				s[i][j] = vv[i][j] + s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
		for(int x = 1; x < n; x++)
			for(int y = 1; y < m; y++)
				for(int len1 = 2; x + len1 - 1 <= n; len1++)
					for(int len2 = 2; y + len2 - 1 <= m; len2++){
						int a = x + len1 - 1, b = y + len2 - 1;
						double temp = cal(x, y, a, b) - cal(x + 1, y + 1, a - 1, b - 1);
						if(temp > ans) ax = x, ay = y, aa = a, ab = b, ans = temp; 
					}
		Tnum kkk = to(1);
		for(int i = ax; i <= aa; i++) kkk *= to(v[i][ay]), kkk *= to(v[i][ab]);
		for(int i = ay + 1; i <= ab - 1; i++) kkk *= to(v[ax][i]), kkk *= to(v[aa][i]);
		kkk.print();
	}
}

100 pts

O ( n 4 ) O(n^4) O(n4) 的复杂度还是太高了,所以我们考虑能不能优化掉一维之类的。

  首先我们更换枚举方式,先枚举矩形的上界和下界 a , b a, b a,b,再枚举左界 c c c,注意左界是从 m m m 1 1 1 反着枚举的。考虑能不能 O ( 1 ) O(1) O(1) 找到 右界 d d d,首先我们要求的式子就应该是(记录 s x , y , a , b s_{x, y, a, b} sx,y,a,b 右下角为 a , b a, b a,b 左上角为 x , y x, y x,y 的矩形的和):

s a , 1 , a , d + s b , 1 , b , d + s a + 1 , d , b − 1 , d − s a , 1 , a , c − 1 − s b , 1 , b , c − 1 + s a + 1 , c , b − 1 , c s_{a, 1, a, d} + s_{b, 1, b, d} + s_{a + 1, d, b - 1, d} - s_{a, 1, a, c - 1} - s_{b, 1, b, c - 1} + s_{a + 1, c, b - 1, c} sa,1,a,d+sb,1,b,d+sa+1,d,b1,dsa,1,a,c1sb,1,b,c1+sa+1,c,b1,c

  为了式子好看一些,我们记 s u m x = s a , 1 , a , x + s b , 1 , b , x , x u m x = s a + 1 , x , b − 1 , x sum_x = s_{a, 1, a, x} + s_{b, 1, b, x}, xum_{x} = s_{a + 1, x, b - 1, x} sumx=sa,1,a,x+sb,1,b,x,xumx=sa+1,x,b1,x,那么现在式子就变成了这样:

s u m d + x u m d − s u m c − 1 + x u m c sum_d + xum_d - sum_{c - 1} + xum_c sumd+xumdsumc1+xumc

  然后我们发现这里面和 d d d 有关的式子和 c c c 的位置无关,所以我们考虑倒着扫 c c c 然后记录一个 t e m p temp temp 为当前扫过的部分的 s u m d + x u m d sum_d + xum_d sumd+xumd 的最大值,然后每次 c c c 往左移就比较一下新的位置的 s u m d + x u m d sum_d + xum_d sumd+xumd t e m p temp temp 的大小更新这个最大值就做完了。

namespace sub2{
	double s[MAXN][MAXN] = { 0 };
	double vv[MAXN][MAXN] = { 0 };
	inline double cal(int x, int y, int a, int b) { return s[a][b] - s[x - 1][b] + s[x - 1][y - 1] - s[a][y - 1]; }
	inline double xum(int a, int b, int x) { return cal(a + 1, x, b - 1, x); }
	inline double sum(int a, int b, int x) { return cal(a, 1, a, x) + cal(b, 1, b, x); }
	void solve(){
		double ans = 0; int ax, ay, aa, ab;
		for(int i = 1; i <= n; i++)
			for(int j = 1; j <= m; j++) vv[i][j] = log(v[i][j]);
		for(int i = 1; i <= n; i++)
			for(int j = 1; j <= m; j++)
				s[i][j] = vv[i][j] + s[i - 1][j] + s[i][j - 1] - s[i - 1][j - 1];
		for(int a = 1; a <= n; a++)
			for(int b = a + 1; b <= n; b++){
				double temp = 0; int d = m;
				for(int c = m - 1; c >= 1; c--){
					if(temp < sum(a, b, c + 1) + xum(a, b, c + 1))
						temp = sum(a, b, c + 1) + xum(a, b, c + 1), d = c + 1;
					if(ans < temp - sum(a, b, c - 1) + xum(a, b, c)) 
						ax = a, ay = c, aa = b, ab = d, ans = temp - sum(a, b, c - 1) + xum(a, b, c);
				}
			}
		Tnum kkk = to(1);
		for(int i = ax; i <= aa; i++) kkk *= to(v[i][ay]), kkk *= to(v[i][ab]);
		for(int i = ay + 1; i <= ab - 1; i++) kkk *= to(v[ax][i]), kkk *= to(v[aa][i]);
		kkk.print();
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值