題目
降雷皇哈蒙很喜歡雷電,他想找到神奇的電光。
哈蒙有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);
}