题目大意:给出一个数组a,要将一个数修改成[1,300]内的任意一个数,问区间和是完全平方数的区间最多有多少个
1<=n<=300;1<=ai<=300
思路:因为n的范围是300,所以我们可以遍历每一个数,用前缀和维护区间和,统计对于每一个包含这个数的区间,将它修改成哪些数,能够使当前区间的区间和变成完全平方数,那么变成的这个数的贡献就+1,修改后区间和的范围即为[sum[r]-sum[l-1]-a[i]+1,sum[r]-sum[l-1]-s[i]+300],将端点开个方,新的区间内的所有数的平方都能由修改这个数得到
对于不包含这个数的区间,其区间和如果是完全平方数就贡献+1,统计将这个数变成多少能使区间数最多,得到它的最大贡献。
遍历完所有区间后,统计每个位置上这个数的贡献,维护答案的最大值
#include<bits/stdc++.h>
//#include<__msvc_all_public_headers.hpp>
using namespace std;
typedef long long ll;
const int N = 305;
const ll MOD = 998244353;
int a[N];
int sum[N];
void solve()
{
int n;
cin >> n;
for (int i = 1; i <= n; i++)
{
cin >> a[i];
sum[i] = sum[i - 1] + a[i];//用前缀和维护区间和
}
int ans = 0;
for (int i = 1; i <= n; i++)
{
vector<int>cnt(305);
int cnt2 = 0;
for (int j = 1; j <= n; j++)
{
for (int k = j; k <= n; k++)
{//遍历所有区间
if (j <= i && k >= i)
{
int su = sum[k] - sum[j - 1];
int mi = su - a[i] + 1;//这个位置修改后能产生的区间和的最小值
int ma = su - a[i] + 300;//这个位置修改后能产生的区间和的最大值
int x = sqrtl(mi);
if (x * x != mi)
{//找到最小的能被修改成的完全平方数
x++;
}
int y = sqrtl(ma);//最大的能被修改成的完全平方数
for (int l = x; l <= y; l++)
{
cnt[l * l - mi+1]++;//修改成哪些数能使和变成完全平方数
}
}
else
{
int su = sum[k] - sum[j - 1];
int x = sqrtl(su);//对于其他区间,直接判断和是否唯完全平方数
int flag = 0;
for (int temp = x - 5; temp <= x + 5; temp++)
{//避免sqrt精度丢失
if (temp * temp == su)
{
flag = 1;
break;
}
}
cnt2 += flag;
}
}
}
int cnt1 = 0;
for (int j = 1; j <= 300; j++)
{//每个位置修改成哪个数贡献最大
cnt1 = max(cnt1, cnt[j]);
}
ans = max(ans, cnt1 + cnt2);
}
cout << ans << endl;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int t;
cin >> t;
while (t--)
{
solve();
}
return 0;
}