题目链接:http://codeforces.com/contest/1060/problem/C
思路:
一些暴力看起来会超时的题目还是有必要尝试一下的 ;
题目的意思可以转换成:求两个数组的区间和的最大长度和,并且两个区间和的乘积小于等于x
给出的数组只有2000个,求出所有区间和的时间复杂度大概是4*10^6,求两个数组的区间和就只是多一个常数; 假设一个数组的某个区间和是 n,只需要在另一个数组的区间和中二分找 x/n 的值,得到一个下标 p,那么0到p内在数值上是符合题意的,接下来要解决的就是在0到p中找区间长度最长的,才能得到题目要求的最大值;如果这一步仍然用暴力枚举去找就会超时,这里可以通过一个简单的dp处理一下,因为0和p的的区间和是肯定符合题意的,我们只需要用数组记录前i个区间和中最大区间长度是多少就行了,这样就不用一个个遍历,只需要直接取值就行了;
#include <iostream>
#include <cstdio>
#include <cmath>
#include <algorithm>
using namespace std;
const int Maxn = 2e3+10;
struct Node {
int cnt, sum; // cnt 区间长度,sum 区间和
bool operator < (const Node &a1) const {
return sum < a1.sum;
}
} N[Maxn*Maxn], M[Maxn*Maxn];
int sN[Maxn], sM[Maxn], num[Maxn*Maxn];
int main (void)
{
int n, m, x, tmp;
scanf ("%d%d", &n, &m);
for (int i = 1; i <= n; ++i) {
scanf ("%d", &tmp);
sN[i] = sN[i-1]+tmp;
}
for (int i = 1; i <= m; ++i) {
scanf ("%d", &tmp);
sM[i] = sM[i-1]+tmp;
}
scanf("%d", &x);
int n1, m1;
n1 = 0;
for (int i = 1; i <= n; ++i) {
for (int j = i; j <= n; ++j) {
if(sN[j]-sN[j-i] > x) continue;
N[n1].cnt = i; N[n1].sum = sN[j]-sN[j-i];
n1++;
}
}
m1 = 0;
for (int i = 1; i <= m; ++i) {
for (int j = i; j <= m; ++j) {
if(sM[j]-sM[j-i] > x) continue;
M[m1].cnt = i; M[m1].sum = sM[j]-sM[j-i];
m1++;
}
}
int ans = 0, p, index;
sort (N, N+n1); sort (M, M+m1);
num[0] = M[0].cnt;
for (int i = 1; i < m1; ++i) { // num[i] 为M[]的前i个区间长度的最大值
num[i] = max (num[i-1], M[i].cnt);
}
for (int i = 0; i < n1; ++i) {
index = x/N[i].sum;
int L = 0, R = m1, mid;
while (L < R) {
mid = (L+R)/2;
if (M[mid].sum > index) R = mid;
else L = mid+1;
}
if (--R < 0) continue; // 上面的二分求得是大于index的,要-1
ans = max (ans, N[i].cnt*num[R]);
}
printf ("%d\n", ans);
return 0;
}