Codeforces Round #632 (Div. 2) 比赛人数12810
[codeforces 1333C] Eugene and an array 寻找位置i所辖的最远位置
总目录详见https://blog.csdn.net/mrcrack/article/details/103564004
在线测评地址https://codeforces.com/contest/1333/problem/C
Problem | Lang | Verdict | Time | Memory |
---|---|---|---|---|
C - Eugene and an array | GNU C++17 | Accepted | 109 ms | 5500 KB |
造了两组数据,手工算法模拟如下
6
1 2 3 -5 2 3
12
数组a的脚标 1 2 3 4 5 6
数组a的值 1 2 3 -5 2 3
数组a的前缀和 1 3 6 1 3 6
good subarrays如下
[1],[1,2],[1,2,3] 值1(位置1) 对应的右边界是 值3(位置3)
找到与位置1,相同前缀和(1)的位置4,位置4-1=3,即为位置3
[2],[2,3] 值2(位置2) 对应的右边界是 值3(位置3)
找到与位置2,相同前缀和(3)的位置5,位置5-1=4(下面数据会用到的位置4).
位置4与(上面位置1对应的边界)位置3找最小值,即为位置3
[3],[3,-5] 值3(位置3) 对应的右边界是 值-5(位置4)
找到与位置3,相同前缀和(6)的位置6,位置6-1=5(下面数据会用到的位置4).
位置5与(上面位置2对应的边界)位置4找最小值,即为位置4
[-5],[-5,2] 值-5(位置4) 对应的右边界是 值2(位置5)
找不到与位置4,相同前缀和(1)的位置,那就用默认的位置6(下面数据会用到的位置6).
位置6与(上面位置3对应的边界)位置5找最小值,即为位置5
[2],[2,3] 值2(位置5) 对应的右边界是 值3(位置6)
找不到与位置5,相同前缀和(3)的位置,那就用默认的位置6(下面数据会用到的位置6).
位置6与(上面位置4对应的边界)位置6找最小值,即为位置6
[3] 值3(位置6) 对应的右边界是 值3(位置6)
找不到与位置5,相同前缀和(6)的位置,那就用默认的位置6.
位置6与(上面位置4对应的边界)位置6找最小值,即为位置6
若觉得文字太罗嗦,请看数据生成过程
数组a的脚标 1 2 3 4 5 6
数组a的值 1 2 3 -5 2 3
数组a的前缀和 1 3 6 1 3 6
right(初始化) 6 6 6 6 6 6
若觉得文字太罗嗦,请看数据生成过程
数组a的脚标 1 2 3 4 5 6
数组a的值 1 2 3 -5 2 3
数组a的前缀和 1 3 6 1 3 6
right(根据前缀和,进行生成) 3 4 5 6 6 6
若觉得文字太罗嗦,请看数据生成过程
数组a的脚标 1 2 3 4 5 6
数组a的值 1 2 3 -5 2 3
数组a的前缀和 1 3 6 1 3 6
right(逆向取最小值) 3 3 4 5 6 6
ans=(3-1+1)+(3-2+1)+(4-3+1)+(5-4+1)+(6-5+1)+(6-6+1)=12
8
1 2 0 3 4 0 5 6
9
数组a的脚标 1 2 3 4 5 6 7 8
数组a的值 1 2 0 3 4 0 5 6
数组a的前缀和 1 3 3 6 10 10 15 21
good subarrays如下
[1],[1,2] 值1(位置1) 对应的右边界是 值2(位置2)
[2] 值2(位置2) 对应的右边界是 值2(位置2)
[0] 值0(位置3) 对应的右边界是 值2(位置2)
[3],[3,4] 值3(位置4) 对应的右边界是 值4(位置5)
[4] 值4(位置5) 对应的右边界是 值4(位置5)
[0] 值0(位置6) 对应的右边界是 值4(位置5)
[7],[7,8] 值7(位置7) 对应的右边界是 值8(位置8)
[8] 值8(位置8) 对应的右边界是 值8(位置8)
请看数据生成过程
数组a的脚标 1 2 3 4 5 6 7 8
数组a的值 1 2 0 3 4 0 5 6
数组a的前缀和 1 3 3 6 10 10 15 21
right(初始化) 8 8 8 8 8 8 8 8
请看数据生成过程
数组a的脚标 1 2 3 4 5 6 7 8
数组a的值 1 2 0 3 4 0 5 6
数组a的前缀和 1 3 3 6 10 10 15 21
right(根据前缀和,进行生成) 8 2 8 8 5 8 8 8
请看数据生成过程
数组a的脚标 1 2 3 4 5 6 7 8
数组a的值 1 2 0 3 4 0 5 6
数组a的前缀和 1 3 3 6 10 10 15 21
right(逆向取最小值) 2 2 2 5 5 5 8 8
注意right[i]=min(right[i],right[i-1]);right[i]=min(right[i],right[i+1])
ans=(2-1+1)+(2-2+1)+(2-3+1)+(5-4+1)+(5-5+1)+(8-7+1)+(8-8+1)=9
AC代码如下
#include <cstdio>
#include <algorithm>
#define maxn 200010
#define LL long long
using namespace std;
LL sum[maxn],ans;
struct node{
int seq;//记录序列
LL sum;//记录前缀和
}b[maxn];
int right[maxn];//right[i]代表位置i能管到的有效最远位置
int cmp(node a,node b){
return a.sum==b.sum?a.seq<b.seq:a.sum<b.sum;
}
int main(){
int i,a,n;
scanf("%d",&n);
for(i=1;i<=n;i++)scanf("%d",&a),sum[i]=sum[i-1]+a;//前缀和计算
for(i=0;i<=n;i++)b[i].seq=i,b[i].sum=sum[i];//i=0左边界设置
sort(b+0,b+1+n,cmp);
for(i=0;i<=n+1;i++)right[i]=n;//i=n+1右边界设置
for(i=1;i<=n;i++)
if(b[i].sum==b[i-1].sum)
right[b[i-1].seq]=b[i].seq-1;//根据前缀和计算
for(i=n;i>=1;i--)right[i]=min(right[i],right[i+1]),right[i]=min(right[i],right[i-1]);//逆向取最小值
for(i=1;i<=n;i++)ans+=right[i]-i+1;
printf("%lld\n",ans);
}