2017-HDNOIP-提高组1-小鱼干
Posted 小蒟蒻
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2017-HDNOIP-提高组1-小鱼干相关的知识,希望对你有一定的参考价值。
小鱼干
【问题描述】
小喵喵有n个小鱼干排成一列,其中第i个小鱼干有两种属性,美味度ai和特殊度bi。
现在小喵喵要吃掉一些小鱼干,出于一些原因,小喵喵会吃掉连续的一段区间中的所有小鱼干。
如果吃掉了[l,r]一段区间,那么小喵喵会获得一些满意度。
形式化地,总满意度=。
由于只有小喵喵最喜欢的小鱼干的特殊度等于1,所以bi=1的小鱼干数量不会超过400个,其他的bi=0。
现在小喵喵可以选择任意一段区间,但是有一些小鱼干的美味度是负数,吃掉所有小鱼干不一定会获得最多的满意度。所以小喵喵想知道最大能获得的总满意度是多少。
【输入】
第一行一个整数n,表示小鱼干的数量。
第二行n个整数,第i个数为ai,表示美味度。
第三行n个整数,第i个数为bi,表示特殊度。
【输出】
一行一个整数,表示最大的总满意度。
【输入输出样例】
fish.in |
fish.out |
5 4 -2 2 -3 1 0 0 1 0 0 |
8 |
【样例解释】
吃掉前三个小鱼干会获得最多的满意度。其中8=(4+(-2)+2)*(1+0+0+1)
【数据范围】
测试数据编号 |
数据范围 |
其他限制 |
1 - 12 |
1≤N≤1000 |
|
13 - 16 |
1≤N≤100000 |
所有bi=0 |
17 - 18 |
1≤N≤100000 |
bi=1的i的数量不超过20 |
19 - 20 |
1≤N≤100000 |
|
对于100%的数据:n≤100000,-10^9≤ai≤10^9,bi=0 or 1,bi=1的i的数量不超过400。
对于另外0%的数据:n≤100000,小喵喵会随机地给每个小鱼干的属性赋为-10^9≤ai,bi≤10^9。并且满意度变为总满意度=
【提示】
请注意本题中的数字1与字母l的区别。(你可以根据需要缩放页面比例)
其中。
考试的时候看到这道题,我的内心是崩溃的。一个是因为对求和符号抱有自然的恐惧,另一个就是感觉数据量有点大。想了半天,最后还是用了前缀和+暴力,其中特殊考虑了一下全部a都为负的情况。得分60(也就是前12个点),后面的点时间超限。代码如下:
1 #include <iostream> 2 #include <cmath> 3 #include <cstring> 4 #include <cstdio> 5 #include <cstdlib> 6 #include <algorithm> 7 using namespace std; 8 long long a[101010]; 9 int b[101010]; 10 int main() 11 { 12 int n; 13 scanf("%d",&n); 14 bool ok=false; 15 a[0]=0;b[0]=0; 16 for(int i=1;i<=n;i++) 17 { 18 long long x; 19 scanf("%lld",&x); 20 a[i]=a[i-1]+x; 21 //printf("%lld ",a[i]); 22 if(x>0) ok=true; 23 } 24 long long maxn=-999999999; 25 for(int i=1;i<=n;i++) 26 { 27 int y; 28 scanf("%d",&y); 29 if(!ok) maxn=max(maxn,(a[i]-a[i-1])*(y+1)); 30 b[i]=b[i-1]+y; 31 } 32 if(!ok) {printf("%lld",maxn);return 0;} 33 long long ans=-999999999; 34 for(int i=1;i<=n;i++) 35 { 36 for(int j=0;j<i;j++) 37 { 38 long long sum=(a[i]-a[j])*(b[i]-b[j]+1); 39 ans=max(ans,sum); 40 } 41 } 42 printf("%lld",ans); 43 return 0; 44 }
后来考完之后,我看了一些AC的代码,发现他们的方法都惊人的相似。
他们都是记录了b中1的位置,然后按1的位置把一长串数分为几部分,然后:①在每段内求最大连续和;②考虑一段内b都是0的是否存在最大。
大神代码如下:
1 #include<iostream> 2 #include<cstdio> 3 #include<cstdlib> 4 #include<algorithm> 5 #include<cstring> 6 #include<cmath> 7 using namespace std; 8 long long read() 9 { 10 long long x=0,f=1;char ch=getchar(); 11 while(!isdigit(ch)){if(ch==\'-\') f=-1;ch=getchar();} 12 while(isdigit(ch)){x=x*10+ch-\'0\';ch=getchar();} 13 return x*f; 14 } 15 long long n; 16 long long a[100001]; 17 long long b[100001]; 18 long long suma[100001],sumb[100001]; //前缀和 19 long long add[500]; //(前一个1的位置,当前1的位置]中间的连续和最大值 20 long long vis[500]; //b中值为1的数的位置 21 long long cnt; 22 long long ans=0; 23 int main() 24 { 25 n=read(); 26 for(int i=1;i<=n;i++){a[i]=read();suma[i]=suma[i-1]+a[i];} 27 for(int i=1;i<=n;i++){b[i]=read();sumb[i]=sumb[i-1]+b[i];if(b[i]==1) vis[++cnt]=i;} 28 memset(add,-97,sizeof(add)); 29 vis[cnt+1]=n+1; //定义边界 30 for(int i=1;i<=cnt;i++) 31 { 32 long long temp=0; 33 for(int j=vis[i];j>vis[i-1];j--){temp+=a[j];add[i]=max(add[i],temp);} //找到每两个1之间的最大联系和 34 } 35 for(int i=1;i<=n;i++) /*找到几个连续段结合起来的最大*/ 36 { 37 ans=max(ans,suma[i]*sumb[i]); //乘积大于2^64是才会用得到高精度。本题不用 38 for(int j=1;j<=sumb[i]/*有这么多个1*/;j++)ans=max(ans,(add[j]+suma[i]-suma[vis[j]])*(sumb[i]-j+2)); //分段考虑取最大 39 } 40 for(int i=0;i<=cnt;i++) /*以防某一段(b都是0)全部加起来是最大*/ 41 { 42 long long w=0; 43 for(int j=vis[i]+1;j<vis[i+1];j++) {w=max(w+a[j],a[j]);ans=max(ans,w);} //b全部为0的每段 44 } 45 printf("%lld",ans); 46 return 0; 47 }
以上是关于2017-HDNOIP-提高组1-小鱼干的主要内容,如果未能解决你的问题,请参考以下文章