【题解】P8663 题解
P8663 题解
思路分析
余数分析题。
设满足条件的三数为 ,由题意得 。
于是有 。
又根据余数的性质,,即 。
所以, 或 或 。
于是,我们枚举 , 与 即可,这样便可以 的复杂度遍历 , 与 。
此时问题转化为:已知 , 与 ,求 的最大值。
这个其实直接更新就可以了,记原数组为 ,具体步骤如下:
- 开一个数组 , 代表在 中,模 余 的数的最大值。
- 。
但是需要注意一个问题:数不能重复选。当 , 相同时, 应选择次大的,以此类推。当 , 与 相同时, 与 分别应选择次大和次次大。
于是, 数组应该改成三维的,三维分别表示:
- 代表在 中,模 余 的数的最大值。
- 代表在 中,模 余 的数的次大值。
- 代表在 中,模 余 的数的次次大值。
为什么不从 开始呢?因为这样只要通过 f[j][(i==j)] 就可以算出对应的数,其他同理。
也就是 res = max(res, f[i][0]+f[j][(i==j)]+f[g][(i==g)+(j==g)])。
最后再附上同时计算最大值、次大值、次次大值的算法。
设最大值、次大值、次次大值分别为 ,,,当前输入的数为 。
- 若 ,则 ,,。
- 否则,若 ,则 ,。
- 再否则,若 ,则 。
代码
#include <iostream>
#include <iomanip>
#include <cmath>
#include <string>
#include <algorithm>
#include <cstdio>
#include <cstring>
#define endl '\n'
#define int long long
#define IL inline
using namespace std;
const int N = 1e5 + 10;
const int INF = 0x3f3f3f3f;
IL int read()
{
int x = 0,f = 1;
char c = getchar();
while(c <'0'|| c >'9'){if(c == '-') f = -1;c = getchar();}
while(c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar();
return x * f;
}
void write(int x)
{
if(x < 0) putchar('-'),x = -x;
if(x > 9) write(x / 10);
putchar(x % 10 + '0');
}
int f[N][3];
int a[N];
int res = -1e14;
signed main()
{
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n, k;
cin >> n >> k;
for(int i = 0;i < k;i++) f[i][0] = f[i][1] = f[i][2] = -6e8; //初始化
for(int i = 1;i <= n;i++)
{
cin >> a[i];
int t = a[i];
int u = a[i] % k;
if(f[u][0] < t) //统计最大、次大、次次大
{
f[u][2] = f[u][1];
f[u][1] = f[u][0];
f[u][0] = t;
}
else if(f[u][1] < t)
{
f[u][2] = f[u][1];
f[u][1] = t;
}
else if(f[u][2] < t)
{
f[u][2] = t;
}
}
for(int i = 0;i < k;i++)
{
for(int j = 0;j < k;j++)
{
for(int z = 0;z <= 2 * k;z += k) //枚举每个余数
{
int g = z - i - j;
if(g < 0 || g >= k) continue; //越界跳过
res = max(res, f[i][0] + f[j][(i == j)] + f[g][(i == g) + (j == g)]); //统计答案
}
}
}
cout << res << endl;
return 0;
}

浙公网安备 33010602011771号