降雷皇 【NOIP2017提高組模擬12.10】

題目

降雷皇哈蒙很喜歡雷電,他想找到神奇的電光。
哈蒙有n條導線排成一排,每條導線有一個電阻值,神奇的電光只能從一根導線傳到電阻比它大的上面,而且必須從左邊向右傳導,當然導線不必是連續的。
哈蒙想知道電光最多能通過多少條導線,還想知道這樣的方案有多少。

樣例輸入
第一行兩個整數n和type。type表示數據類型
第二行n個整數表示電阻。
5 1
1 3 2 5 4

樣例輸出
第一行一個整數表示電光最多能通過多少條導線。
如果type=1則需要輸出第二行,表示方案數,對123456789取模。
3
4

數據範圍
對於20%的數據n<=10;
對於40%的數據n<=1000;
對於另外20%的數據type=0;
對於另外20%的數據保證最多能通過不超過100條導線;
對於100%的數據n<=100000,電阻值不超過100000。


剖解題目

給一個序列,求其最長上升子序列的長度已經方案數。


解法

通常的二分求法gg了。。。
一顆權值線段樹,維護前i個數中,以每一個數值結尾的子序列最大長度以及方案數。
假設當前數爲a[i],那麼就在1~a[i]-1中尋找出最大的長度以及其方案數。
更新到a[i]這個位置即可。
時間O(log n)


代碼

#include<cstdio>
#include<algorithm>
#include<cstdlib>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define ll long long

using namespace std;

const int maxn=1e5;
const ll mo=123456789;
struct cy{
    int val;
    ll sum;
}tree[maxn*4+10];
int n,type;
ll num,maxx,ansm,ansn;

void change(int p,int l,int r,int x)
{
    if (l==r){
        if (maxx>tree[p].val) tree[p].val=maxx,tree[p].sum=num;
        else if (maxx==tree[p].val) tree[p].sum=(tree[p].sum+num)%mo;
        return ;
    }
    int mid=(l+r)/2;
    if (x<=mid) change(p<<1,l,mid,x);
    else change(p<<1|1,mid+1,r,x); 

    tree[p].val=max(tree[p<<1].val,tree[p<<1|1].val);
    if (tree[p<<1].val>tree[p<<1|1].val) tree[p].sum=tree[p<<1].sum;
    else if (tree[p<<1].val<tree[p<<1|1].val) tree[p].sum=tree[p<<1|1].sum;
    else tree[p].sum=(tree[p<<1].sum+tree[p<<1|1].sum)%mo; 
}
void find(int p,int l,int r,int a,int b)
{
    if(l==a&&r==b){
        if (tree[p].val>maxx) maxx=tree[p].val,num=tree[p].sum;
        else if (tree[p].val==maxx) num=(tree[p].sum+num)%mo;
        return;
    }
    int mid=(l+r)/2;
    if (b<=mid) find(p<<1,l,mid,a,b);
    else if (a>mid) find(p<<1|1,mid+1,r,a,b);
    else {
        find(p<<1,l,mid,a,mid);
        find(p<<1|1,mid+1,r,mid+1,b);
    }
}
int main()
{
    freopen("hamon.in","r",stdin);
    freopen("hamon.out","w",stdout);
    scanf("%d%d",&n,&type);
    maxx=0; num=1;
    change(1,0,maxn,0);
    fo(i,1,n){
        int x;
        scanf("%d",&x);
        maxx=0; num=0;
        find(1,0,maxn,0,x-1);
        maxx++;
        change(1,0,maxn,x);
        if (maxx>ansm) ansm=maxx,ansn=num;
        else if (maxx==ansm) ansn=(ansn+num)%mo;
    } 
    printf("%d\n",ansm);
    if(type) printf("%lld\n",ansn);
}

這裏寫圖片描述

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章