15 pts 求调!
查看原帖
15 pts 求调!
448873
Pig_py楼主2023/8/9 19:25
#include<bits/stdc++.h>
#define int long long
using namespace std;
int n,a[200005],dp_up[200005],dp_down[200005],ans1,ans2;
const int mod=1000000007;
vector<int>numbers;
int find_numbers(int x){
    return lower_bound(numbers.begin(),numbers.end(),x)-numbers.begin()+1;
}
struct Segment_tree{
    int maximum;
}Tree[1000005];
int ls(int p){return p*2;}
int rs(int p){return p*2+1;}
void pushup(int p){
    Tree[p].maximum=max(Tree[ls(p)].maximum,Tree[rs(p)].maximum);
}
void Build_tree(int p,int l,int r){
    Tree[p].maximum=0;
    if(l==r){
        Tree[p].maximum=0;
        return;
    }
    int mid=(l+r)/2;
    Build_tree(ls(p),l,mid);
    Build_tree(rs(p),mid+1,r);
    pushup(p);
}
bool check1(int l1,int r1,int l2,int r2){
    if(l1>=l2&&l1<=r2)return true;
    if(r1>=l2&&r1<=r2)return true;
    if(l2>=l1&&l2<=r1)return true;
    if(r2>=l1&&r2<=r1)return true;
    return false;
}
void Amend(int p,int l,int r,int ql,int qr,int k){
    if(l==r){
        Tree[p].maximum=max(Tree[p].maximum,k);
        return;
    }
    int mid=(l+r)/2;
    if(check1(l,mid,ql,qr)){
        Amend(ls(p),l,mid,ql,qr,k);
    }
    if(check1(mid+1,r,ql,qr)){
        Amend(rs(p),mid+1,r,ql,qr,k);
    }
    pushup(p);
}
int Query(int p,int l,int r,int ql,int qr){
    if(ql>qr)return 0;
    if(l>=ql&&r<=qr)return Tree[p].maximum;
    int res=0,mid=(l+r)/2;
    if(check1(l,mid,ql,qr))res=max(res,Query(ls(p),l,mid,ql,qr));
    if(check1(mid+1,r,ql,qr))res=max(res,Query(rs(p),mid+1,r,ql,qr));
    return res;
}
long long fastpow(int u,int v){
    if(!v)return 1ll;
    int temp=fastpow(u,v/2);
    temp=(temp*temp)%mod;
    if(v&1)temp=(temp*u)%mod;
    return temp;
}
signed main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;i++){
        scanf("%lld",&a[i]);
        numbers.push_back(a[i]);
    }
    sort(numbers.begin(),numbers.end());
    numbers.erase(unique(numbers.begin(),numbers.end()),numbers.end());
    for(int i=1;i<=n;i++){
        a[i]=find_numbers(a[i]);
    }
    Build_tree(1,1,numbers.size());
    for(int i=n;i>=1;i--){
        int res=Query(1,1,numbers.size(),1,a[i]-1)+1;
        dp_down[i]=max(1ll,res);
        Amend(1,1,numbers.size(),a[i],a[i],dp_down[i]);
    }
    Build_tree(1,1,numbers.size());
    for(int i=n;i>=1;i--){
        int res=Query(1,1,numbers.size(),a[i]+1,numbers.size())+1;
        dp_up[i]=max(1ll,res);
        Amend(1,1,numbers.size(),a[i],a[i],dp_up[i]);
    }
    for(int i=1;i<=n;i++){
        ans1=max(ans1,dp_up[i]+dp_down[i]-1);
    }
    printf("%lld ",ans1);
    for(int i=1;i<=n;i++){
        if(dp_up[i]+dp_down[i]-1==ans1){
            ans2=(ans2+fastpow(2,n-ans1))%mod;
        }
    }
    printf("%lld",ans2);
}
/*
我们考虑写出数字的最优情况
显然最优情况要尽可能保证最长严格递增子序列最长
这是一个没有见过的套路:枚举第一个数,求出 LIS 和 LDS 即可
注意到严格递增,所以 {LIS}∩{LDS}={x}
其中 x 表示第一个数
*/
2023/8/9 19:25
加载中...