AcWing 1234. 倍数问题---关于负数模K的问题总结
原题链接
中等
作者:
Jocelin
,
2021-04-03 16:24:19
,
所有人可见
,
阅读 724
#include<iostream>
#include<vector>
#include<cstring>
#include<algorithm>
// C++ 的取模正数是正数,负数是负数,
//而真正意义上的取模符号结果都是正的比如 -1 % 2 用C++的结果是-1而实际真正的结果是1,(数学上模的结果都是正的)
//所以会看到 (____ % k + k ) % k 解决上面的问题 比如-5 % 3 = 1;
//而C++中-5 % 3 的结果是 -2 ,我们通过 ((-5 % 3) + 3) % 3 = 1 ;这样就得到真正的结果
using namespace std;
// #define N 100010
// int a[N];
// int f[100001][3][1001];
#define N 1010
vector<int> a[N];
int f[4][N];
int main()
{
//背包去做,前面一维是i个物品,后面几维就是限制,一个限制一维,一般的只有体积只加一维
//这里有两个限制,一个是三个数,一个是k的倍数
//从i个数中选,且已经选了j个数,且总和模KK的余数是k的选法 的集合
//优化:由于 ( a + b + c ) % k,
//我们不需要管abc本身,只需要考虑他们的余数就可以了,我们最后取最大的数的余数即可
//这样我们把10^5个数对K取模, 结果就在0~k的取值中间,所以我们把10^5压缩到了 3000(3*1000),1000是k的取值范围
// for(int i = 0; i <=n;i++)
// {
// for(int j = 1; j <=3 ;j++)//个数
// {
// for(int k = 0; k <KK;k++) //当前模以k 的余数
// {
// f[i][j][k] = f[i-1][j][k];//不选
// //选的话,就是从i-1中选,前面选了j-1个数,
// //(前面选的数+ a[i] ) % K = k ---> 前面选的数 = ( k - a[i] )%K
// f[i][j][k] = max( f[i][j][k], f[i-1][j-1][ ( ( k - a[i] )%KK + KK )% KK] + a[i]);
// }
// }
// }
int n,m;
cin >> n >> m;
for (int i = 0; i < n; i ++ )
{
int x;
scanf("%d", &x);
a[x % m].push_back(x); //每个数的余数存到一个二维数组里面
}
memset(f, -0x3f, sizeof f);
f[0][0] = 0;
for (int i = 0; i < m; i ++ )
{
sort(a[i].begin(), a[i].end());
reverse(a[i].begin(), a[i].end());
//选三个数这里没有太懂,就是每个余数中选三个最大的,
//想了一下:刚好有可能三个最大数都是 这个余数的三个数相加
for (int u = 0; u < 3 && u < a[i].size(); u ++ )
{
int x = a[i][u];
for (int j = 3; j >= 1; j -- )
for (int k = 0; k < m; k ++ )
f[j][k] = max(f[j][k], f[j - 1][((k - x) % m + m) % m] + x);
}
}
cout << f[3][0];
return 0;
}
为什么y总给的代码j是倒序的呀,感觉需要正序
ok我懂了,假设此时i=3,已经计算完,当计算i=4的时候会用到i=3时候的f[j][k],如果j是正序的话,有可能用的就不是i=3时候的解,而是i=4,会产生状态覆盖和有些情况不被考虑进来
a[x % m].push_back(x)这为啥是二维数组?定义的不是一维数组吗?
vector[HTML_REMOVED] a[N] 表示的是N个vector[HTML_REMOVED], vector可以理解为一维数组,有N个,所以是二维数据
嗯嗯,理解了