关于序列中问题

一般都是dp[i]表示以第i个字符为结束的【某问题】(如连续最大值,连续序列之和大于0的最大长度,不递减序列之和的最值)的值,都是以这个为基础出发,然后求整体的最值。

有感而发吧

干物妹小埋 (不递减序列之和的最大值)

 

题目内容

思路:h[i]是桌子的高,找到前面比比他矮的最大值max{ dp[j] + happy[i] } ( j < i , h[j] <= h[i] ) 可以用线段树,树状数组优化,

线段树实现:

#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
const int maxnn=1e6+5;
int mod=1e9+7;
 
#define pi 3.14159265357
#define ll long long
#define IOS cin.sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define pb push_back
#define mp make_pair
//#define fio(n) (int i=0; i<n; ++i)
//#define fjo(n) (int j=0; j<n; ++j)
 
ll b[maxn],sum[maxn<<2];
int h[maxn];
set<int> s;
map<int,int> mmp;
set<int> ::iterator it;
 
void updata(int rt,int l,int r,int pos,ll val){
    if(l==r){
        sum[rt]=val;
        return ;
    }
    //cout<<1<<endl;
    int mid=(l+r)>>1;
    if(pos<=mid) updata(rt<<1,l,mid,pos,val);
    else updata(rt<<1|1,mid+1,r,pos,val);
    sum[rt]=max(sum[rt<<1],sum[rt<<1|1]);
    return ;
}
 
ll query(int rt,int l,int r,int x,int y){
    ll ans=-1;
    //cout<<2<<endl;
    if(x<=l&&r<=y){
        return sum[rt];
    }
    int mid=(l+r)>>1;
    if(x<=mid) ans=max(ans,query(rt<<1,l,mid,x,y));
    if(y>mid) ans=max(ans,query(rt<<1|1,mid+1,r,x,y));
 
    return ans;
}
 
int main()
{
    std::ios::sync_with_stdio(false);
    int n;
    cin>>n;
    memset(sum,0,sizeof(sum));
    for(int i=0; i<n; ++i){
        cin>>h[i];
        s.insert(h[i]);
    }
    int tot=0;
    for(it=s.begin(); it!=s.end(); ++it){
        mmp[*it]=++tot;//把高度离散化
 
    }
    ll ans=-1;
    for(int i=0; i<n; ++i) cin>>b[i];
    for(int i=0; i<n; ++i){
        int pos=mmp[h[i]];
        ll tmp=query(1,1,tot,1,pos);//找到前面 <=h[i] 的最大happy值,因为是按顺序插入的可以保证 当前树中的值都是i前面的
        //cout<<tmp<<endl;
        tmp+=b[i];
        ans=max(ans,tmp);
        //cout<<sum[6]<<endl;
        //cout<<ans<<" "<<tmp<<endl;
        updata(1,1,tot,pos,tmp);//更新当先位置的这个高度的最大happy值
    }
    cout<<ans<<endl;
    return 0;
}
View Code

数组数组:

#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+5;
const int maxnn=1e6+5;
int mod=1e9+7;
 
#define pi 3.14159265357
#define ll long long
#define IOS cin.sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define pb push_back
#define mp make_pair
//#define fio(n) (int i=0; i<n; ++i)
//#define fjo(n) (int j=0; j<n; ++j)
 
ll b[maxn],sum[maxn<<2];
int h[maxn];
int n;
set<int> s;
map<int,int> mmp;
set<int> ::iterator it;
inline int lowbit(int x){
    return x&(-x);
}
 
inline void updata(int x,ll val){
    for(int i=x; i<=n; i+=lowbit(i)) sum[i]=max(sum[i],val);
}
 
ll query(int l,int r){
    ll ans=-1;
    int mid=r-lowbit(r)+1;
    int mm=l+lowbit(l);
    if(l==mid) return sum[r];
    if(mid>l) return max(query(l,mid-1),sum[r]);
    else return max(sum[mm],query(mm+1,r));
}
int main()
{
    std::ios::sync_with_stdio(false);
    cin>>n;
    memset(sum,0,sizeof(sum));
    for(int i=0; i<n; ++i){
        cin>>h[i];
        s.insert(h[i]);
    }
    int tot=0;
    for(it=s.begin(); it!=s.end(); ++it){
        mmp[*it]=++tot;
 
    }
    ll ans=-1;
    for(int i=0; i<n; ++i) cin>>b[i];
    for(int i=0; i<n; ++i){
        int pos=mmp[h[i]];
        //cout<<pos<<endl;
        ll tmp=query(1,pos);
        //cout<<tmp<<endl;
        tmp+=b[i];
        ans=max(ans,tmp);
        //cout<<sum[6]<<endl;
        //cout<<ans<<" "<<tmp<<endl;
        updata(pos,tmp);
    }
    cout<<ans<<endl;
    return 0;
}
View Code

小阳买水果 (连续序列之和大于0的最大长度)

 

题目描述 
水果店里有 
n
n个水果排成一列。店长要求顾客只能买一段连续的水果。
小阳对每个水果都有一个喜爱程度 
a
i
ai,最终的满意度为他买到的水果的喜欢程度之和。
如果和为正(不管是正多少,只要大于 
0
0 即可),他就满意了。
小阳想知道在他满意的条件下最多能买多少个水果。
你能帮帮他吗?
输入描述:
第一行输入一个正整数 n,表示水果总数。

第二行输入 n 个整数 
a
i
ai,表示小阳对每个水果的喜爱程度。
输出描述:
一行一个整数表示结果。(如果 1 个水果都买不了,请输出 0)
示例1
输入

5
0 0 -7 -6 1
输出

1
备注:1≤n≤2×10e6,|ai|≤10e3
题目内容

思路:前缀和a[i],然后找比a[i]小的最前面的的那个位置max{ i - j } ( j < i , a[j] < a[i] ) 可以用线段树,树状数组优化,亦可以排一下序然后比较一下(看别人的)

把前缀和从小到大排序,如果前缀和相等把编号大的放前面,然后从前往后遍历,记录遍历过程最小的编号,如果当前的编号大于最小的编号,则更新答案。注意特判n=1的情况就可以

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e6+7;
int n;
struct node{
    int pos,num;
}p[maxn];
bool cmp(node a,node b){
    if(a.num==b.num) return a.pos>b.pos;
    return a.num<b.num;
}

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++){
        int x;
        scanf("%d",&x);
        p[i].num=p[i-1].num+x;
        p[i].pos=i;
    }
    n++;
    int minpos=n;
    int ans=0;
    sort(p+1,p+n+1,cmp);
    for(int i=1;i<=n;i++){
        minpos=min(minpos,p[i].pos); //记录编号最小的位置
        if(minpos<p[i].pos) //当前编号大于记录的最小编号,则更新答案
        ans=max(ans,p[i].pos-minpos);
    }
    printf("%d\n",ans);
    return 0;
}
View Code

 

 

待续。。。





posted @ 2019-07-15 21:55  mrdushe  阅读(189)  评论(0编辑  收藏  举报