D.有趣的区间 原题链接
感觉题解的办法好简单呜呜呜,但是我不会。
这里给出我的做法:
由题意知,只要区间中有一个数为奇数那么该区间就是有趣的区间。
不妨考虑[1,n]的所有区间个数设为s,不管它是否有趣。
那么显然s = (1+n)*n/2
由题意知,只要区间中有一个数为奇数那么该区间就是有趣的区间。
不妨考虑[1,n]的所有区间个数设为s,不管它是否有趣。
那么显然s = (1+n)*n/2
考虑以下例子:
5
1 2 3 4 5
那么列出所有区间就是
(1,1) (1,2) (1,3) (1,4) (1,5)
(2,2) (2,3) (2,4) (2,5)
(3,3) (3,4) (3,5)
(4,4) (4,5)
(5,5)
观察可知有趣区间是:
(1,1) (1,2) (1,3) (1,4) (1,5)
(2,3) (2,4) (2,5)
(3,3) (3,4) (3,5)
(4,5)
(5,5)
那么可以首先
1. 然后只需要枚举每个数字 判断奇偶性
2. 如果当前数字为奇数,那么从该数字开始的所有区间都是有趣的区间,贡献是n-i+1
3. 如果当前数字为偶数,那么要从该数字开始寻找第一次出现的奇数,假设找到的奇数序号是j,那么贡献是n-j+1
很容易写出关键代码:
ll sum = 0;
for(ll i = 1;i<=n;i++)
{
if(a[i]%2==1)
{
sum+=n-i+1;continue;
}
else
{
ll j = i;
while(a[j]%2==0&&j<n)
{//寻找第一次出现的奇数
j++;
}
sum+=n-j+1;
}
}
但是这样的话会超时,观察知数据范围5e5,而这个算法双重循环时间复杂度为O(n^2),评测机一般1s是1e7~1e8,那么显然会超时,再观察代码知,当
a[i]%2==0时,从i到第一次奇数出现的序号j之间,是没有必要枚举的,所以可以双指针优化,每一次找到j后,令i = j,然后时间复杂度就是O(n),就可以AC啦!
ACcode:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll sum;
const int N = 5e5+10;
ll a[N];
int n;
int main()
{
cin>>n;
for(ll i = 1;i<=n;i++)
{
cin>>a[i];
}
ll sum = 0;
for(ll i = 1;i<=n;i++)
{
if(a[i]%2==1)
{
sum+=n-i+1;continue;
}
else
{
ll j = i;
while(a[j]%2==0&&j<n)
{
j++;
}
if(j<n)
{
sum+=n-j+1;continue;
}
if(a[j]%2!=0)
{
sum+=j-i+1;
}
i = j;
}
}
cout<<sum;
}