题意:n堆石头,每次可以挑出来两堆同时减一,如果初始石子和为奇数你可以挑选最少的一堆石子拿走一个,问你有多少个区间满足最后可以把所有石子挑完。
思路:题目可以转化为求一个长度大于等于2的连续子数列,其中最大的元素不大于其它元素和的1/2,网上有相关证明。
所以我们枚举把第i个当做最大元素,找到不满足的左区间,然后找到不满足的右区间,答案减去这个不满足的区间,然后左端点右移继续找,感觉复杂度会爆,没想到还挺快,玄学复杂度。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 3e5 + 10;
ll a[maxn], sum[maxn];
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
int n;
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
{
scanf("%lld", &a[i]);
sum[i] = sum[i - 1] + a[i];
}
ll ans = (ll)n * (n + 1) / 2;
for(int i = 1; i <= n; ++i)
{
ll l = i, r = i;
while(sum[r] - sum[l - 1] < 2 * a[i] && l >= 1) --l; //找到把i为最高点时不满足的左端点
++l;
for(int j = l; j <= i; ++j)
{
while(sum[r] - sum[j - 1] < 2 * a[i] && r <= n) ++r; //找到j为左端点时不满足的右端点
--r;
ans -= (r - i + 1); //答案减去不满足的区间
}
}
printf("%lld\n", ans);
}
return 0;
}