HDU 4991 線段樹 Ordered Subsequence
最近在做一套線段樹 | | 樹狀陣列的題目,感覺題目不錯,分享一下
A numeric sequence of a i is ordered if a 1<a 2<……<a N. Let the subsequence of the given numeric sequence (a 1, a 2,……, a N) be any sequence (a i1, a i2,……, a iK), where 1<=i 1<i 2 <……<i K<=N. For example, sequence (1, 7, 3, 5, 9, 4, 8) has ordered subsequences, eg. (1, 7), (3, 4, 8) and many others.
Your program, when given the numeric sequence, must find the number of its ordered subsequence with exact m numbers.
Input
Multi test cases. Each case contain two lines. The first line contains two integers n and m, n is the length of the sequence and m represent the size of the subsequence you need to find. The second line contains the elements of sequence - n integers in the range from 0 to 987654321 each.
Process to the end of file.
[Technical Specification]
1<=n<=10000
1<=m<=100
Output
For each case, output answer % 123456789.
Sample Input
3 2 1 1 2 7 3 1 7 3 5 9 4 8
Sample Output
2 12
然後又做到了一道沒有解析的題目,打算搞一搞
這道題,帶一點遞推,至於怎麼遞推,還需要自己慢慢去找規律,先提示一下,可以開 maxn*100的二維陣列,層層遞推,也就相當於100顆線段樹,用這一層的結果推下一層的。
然後就進行相關的操作,先查詢上一層比它大的和,再更新,對於每一個點更新m次,m次遞推。
演算法複雜度是n*m*log(n)。
大家一定要有一些基礎,因為我是做過一些類似的題了的。就是遇到一個值,就在這個值所對應的點插入線段樹,最後查詢的時候查詢比這個值大的就行了(或者小的)
建議大家先從基礎做起 POJ 2299 HDU 2838
然後再做這一題
下面自己找的優秀的程式碼,別人是用樹狀陣列寫的,明顯快一些。
我是用線段樹寫的,思路都差不多。
下面是我寫的
#include <iostream>
#include <cstdio>
#include<map>
#include <cstring>
#include<vector>
#include <string>
#include<map>
#include<algorithm>
#include<cmath>
#include<set>
#define mem(a,val) memset(a,val,sizeof a)
#define lef rt<<1
#define rig rt<<1|1
#define fori(l,r) for( int i = l ; i <= r ; i++ )
#define forj(l,r) for( int j = l ; j <= r ; j++ )
#define mid (l+r)>>1
#define inf 0x3f3f3f3f
typedef long long ll;
using namespace std;
int n,m;
const int maxn = 1e4+4;
int a[maxn],cpy[maxn];
const int mod = 123456789;
int L,R;
ll ans;
int tree[104][maxn<<2];
void change( int rt,int row )
{
tree[row][rt] = ( tree[row][lef]+tree[row][rig] )%mod;
}
int query( int l,int r,int rt,int row )
{
if( l >= L && r <= R )
return tree[row][rt];
int m = mid;
int ans = 0;
if( m >= L )
ans = ( ans+query(l,m,lef,row) )%mod;
if( m < R )
ans = ( ans+query(m+1,r,rig,row) )%mod;
return ans;
}
void update( int l,int r,int rt,int position,int val,int row )
{
if( l == r )
{
tree[row][rt] = ( tree[row][rt]+val )%mod;
return;
}
int m = mid;
if( m >= position )
update(l,m,lef,position,val,row);
else update(m+1,r,rig,position,val,row);
change(rt,row);
}
void getsum( int l,int r,int rt,int row )
{
if( l == r )
{
ans = ( ans+(ll)tree[row][rt] )%mod;
//cout<<" part ans "<<tree[row][rt]<<" ";
return;
}
int m = mid;
getsum(l,m,lef,row);
getsum(m+1,r,rig,row);
}
int main()
{
while( scanf("%d %d",&n,&m) == 2 )
{
mem(tree,0);
fori(1,n)
{
scanf("%d",&a[i]);
cpy[i] = a[i];
}
if( m == 1 )
{
printf("%d\n",n);
continue;
}
// ************************************
sort(cpy+1,cpy+1+n);
int cnt = unique(cpy+1,cpy+1+n)-cpy; //離散化
fori(1,n)
a[i] = lower_bound(cpy+1,cpy+1+cnt,a[i])-cpy;
//*************************************
int t;
int temp;
R = cnt;
ans = 0;
for( int i = n ; i >= 1 ; i-- )
{
L = a[i]+1;
if( L <= R )
for( int k = 1 ; k <= m-1 ; k++ )
{
temp = query(1,cnt,1,k-1);
if( k == m-1 )
ans = (ans+(ll)temp)%mod;
update(1,cnt,1,a[i],temp,k); //點更新,在a[i]處加temp
}
update(1,cnt,1,a[i],1,0); //最下面一層更新
}
ans = tree[m-1][1]; //直接得到m長的和
printf("%I64d\n",ans);
}
return 0;
}
/*
6 2
1 3 4 6 2 4
*/
這次沒有詳細的解釋,因為我相信你們寫的出來,因為我都寫出來了