习题 8-18 UVA - 1619 Feel Good 感觉不错 (容斥定理)

来源:互联网 发布:linux lnmp安装目录 编辑:程序博客网 时间:2024/06/08 09:25

大体题意:

给你一个长度为n (n <= 100000)的正整数序列ai,求出一段连续子序列a1,,ar 使得 (a1 + a2+ a3 +... ar) * min (a1,a2,a3,,,,ar)尽量大 如果多解任意输出一个!

思路:

思路是比较清晰的,就是有坑:

用sum[i]表示 1 ...i 的和,l[i],r[i],分别表示以第 i 个数字为最小值所能扩展的最左端和最右端!

最后遍历i  更新ans

ll ans = a[i] * (sum[r[i]] - sum[l[i]-1]);

取个最大值即可!

求l 和r 数组还不能暴力求,这样会超时。

        for (int i = 1; i <= n; ++i)
            while(a[l[i]-1] >= a[i])l[i] = l[l[i]-1];

这样求得话  因为遍历到i 时,l[i] 肯定等于i 的,所以当i的位置前一个数值大于等于 第i 个数值时,第i个数值就应该扩展到  第i个数 前一个位置的数 所能扩展到的位置!

r数组 同理。

最后是更新ans

记录下标时 pl 记录l  pr 记录r   他们必须初始化,因为刚上来可能是0嘛! 数据问题!

然后MAX 初始化为0 在与ans 不断比较就可以了

 

#include<cstdio>#include<cstring>#include<algorithm>#define fin freopen("cin.txt","r",stdin);#define fout freopen("out.txt","w",stdout);using namespace std;typedef long long ll;const int INF = 1e9+5;const int maxn = 100000 + 10;int n,a[maxn];ll sum[maxn];int pl,pr,cnt;int l[maxn],r[maxn];int main(){//    fin;    while(scanf("%d",&n) == 1){        for (int i = 1; i <= n; ++i){            scanf("%d",&a[i]);            sum[i] = sum[i-1] + a[i];            l[i] = r[i] = i;        }        a[0] = -INF;        a[n+1] = -INF;        for (int i = 1; i <= n; ++i)            while(a[l[i]-1] >= a[i])l[i] = l[l[i]-1];        for (int i = n; i >= 1; --i)            while(a[r[i]+1] >= a[i])r[i] = r[r[i]+1];//        printf("start\n");//        for (int i = 1; i <= n; ++i)printf("%d ",a[i]);//        printf("\n");//        for (int i = 1; i <= n; ++i)printf("%d ",l[i]);//        printf("\n=\n");//        for (int i = 1; i <= n; ++i)printf("%d ",r[i]);//        printf("\n");        ll MAX = 0;        pl = pr = 1;        for (int i = 1; i <= n; ++i){            ll ans = a[i] * (sum[r[i]] - sum[l[i]-1]);            if (ans > MAX){//                printf("%lld\n",ans);                MAX = ans;                pl = l[i];                pr = r[i];            }        }        if (cnt++)printf("\n");        printf("%lld\n%d %d\n",MAX,pl,pr);    }    return 0;}



0 0
原创粉丝点击