K - I love max and multiply (HDU - 6971)

题目大意

给出 a 和 b 要求求一个c ck满足 ck = max(ai * bj} 且 k <= i & j 求c的总和

思路

很显然 i & j 只会生成小于等于i或j的数
还是举例说明比较清楚 :
比如k=10010 那么 i 和 j 可以选择 1xx1x的数字 所以我们可以从大到小遍历 维护所有1xx1x的最大值
即 A[10010] = max{A[10010], A[10011], A[10110], A[11010]};
为什么只求相对于10010变换一位0的数字的最大值呢 因为变换两位的在前面已经维护完了
因为A[10110] = max(A[10111], A[11110],A[10110]), 所以就不用再枚举这两个的最大值了
再举个简单点的例子
因为A[101] = max(A[101], A[111]), 所以A[100] = max(A[100],A[101],A[110])
然后要注意倒序求值 因为前面的都是根据后面的最大值来更新的
还有一点是ab可能是小于0的数 所以每次维护都要维护一个最小值一个最大值

代码

#include <bits/stdc++.h>

using namespace std;

typedef long long LL;

const int N = 2e6 + 10, INF = 1e9 + 7;
const LL P = 998244353;

int n;
int a[N], b[N], A[N], B[N];

int main()
{
	cin.tie(0);
	ios::sync_with_stdio(false);	
	
	int T;
	cin >> T;
	
	while (T -- )
	{
		cin >> n;
		
		for (int i = 0; i < n; i ++ )
		{
			cin >> a[i];
			A[i] = a[i];
		}
		
		for (int i = 0; i < n; i ++ )
		{
			cin >> b[i];
			B[i] = b[i];
		}
		
		int m = 1;
		while (m < n) m <<= 1;
		for (int i = n; i <= m; i ++ )
		{
			A[i] = B[i] = -INF;
			a[i] = b[i] = INF;
		}
		
		for (int i = n -1 ; i >= 0; i -- )
			for (int j = 1; j < m; j <<= 1)
				if (!(i & j))
				{
					A[i] = max(A[i], A[i ^ j]);
					B[i] = max(B[i], B[i ^ j]);
					a[i] = min(a[i], a[i ^ j]);
					b[i] = min(b[i], b[i ^ j]);
				}
		
		LL ans = 0;
		LL t = -(LL)INF * INF;
		for (int i = n - 1; i >= 0; i -- )
		{
			
			t = max(t, (LL)A[i] * B[i]);
			t = max(t, (LL)A[i] * b[i]);
			t = max(t, (LL)a[i] * B[i]);
			t = max(t, (LL)a[i] * b[i]);
			ans = (ans + t) % P;
		}
		ans = (ans + P) % P;
		cout << ans << endl;
	}
	
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值