P3131 [USACO16JAN] Subsequences Summing to Sevens S
题目链接:
直接暴力的话时间复杂度为 \(O(n^2)\),显然会 \(\sf TLE\)。
#include <bits/stdc++.h>
using namespace std;
const int N = 5e4 + 10;
int a[N], S[N];
int main()
{
ios::sync_with_stdio(false), cin.tie(nullptr);
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i];
S[i] = S[i - 1] + a[i];
}
bool flag = false;
int ans = 0;
for (int len = n; len >= 1; len--) {
for (int i = 1; i + len - 1 <= n; i++) {
int j = i + len - 1;
if ((S[j] - S[i-1]) % 7 == 0) {
ans = max(ans, len);
flag = true;
}
}
}
if (!flag) cout << 0;
else cout << ans;
return 0;
}
考虑到性质:若要让 $ (a[j]-a[i-1]) \bmod 7$ 为 \(0\),只需让 $ a[j]$ 和 \(a[i-1]\) 模 \(7\) 的余数相等即可。
所以只要求出相同余数第一次出现和最后一次出现之间的距离即可。(直接相减,即为\((j-i+1)\))
从前往后依次遍历可以找到某数最后一次出现的下标,同样从后往前依次遍历可以找到某数第一次出现的下标。
#include <bits/stdc++.h>
const int N = 5e4 + 10;
int a[N], first[N], last[N];
int main()
{
std::ios::sync_with_stdio(false), std::cin.tie(nullptr);
int n;
std::cin >> n;
for (int i = 1; i <= n; i++) {
std::cin >> a[i];
a[i] = (a[i - 1] + a[i]) % 7;//模 7 意义下的前缀和,即为前缀和模 7 的余数
}
for (int i = n; i >= 1; i--) {
first[a[i]] = i;//first[x] 表示模 7 余数为 x 的数第一次出现的下标
}
first[0] = 0;//极为重要!
for (int i = 1; i <= n; i++) {
last[a[i]] = i;//last[x] 表示模 7 余数为 x 的数最后一次出现的下标
}
int ans = 0;
for (int i = 0; i < 7; i++) {
ans = std::max(ans, last[i] - first[i]);
}
std::cout << ans;
return 0;
}
如不加 \(\rm first[0]=0\) 的话,当从头一直加到下标为 \(i\) 的前缀和是 \(7\) 的倍数时,模 \(7\) 意义下的前缀和 \(a[i]=0\),这时必须把 \(\rm first[0]\) 置为 \(0\) 才说明把 \(1 \sim i\) 的这些数都选上了。

浙公网安备 33010602011771号