Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 114 Accepted Submission(s): 58
1003 Ordered Subsequence
首先数字有1万个,先离散化一下,把所有数字对应到1到n之间。这样对结果不影响。
dp[i][j]代表以第i个数字结尾上升子序列长度为j的种数。
dp[i][j]=sum{dp[k][j-1]} for each a[k]<a[i]&&k<i
直接写循环会超时。需要优化。
可以用平衡树进行优化,上述的循环过程可以看成是一个区间求和过程。用线段树或者树状数组可以解决。
这样最终的复杂度是n*m*log(n)
这里我用100个数组数组搞了搞,注意中间的取模
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<set>
#include<stack>
#include<map>
#include<ctime>
#define maxn 10010
#define LL long long
#define INF 999999
#define mod 123456789LL
using namespace std;
struct node
{
int id;
LL val;
bool operator <(const node&s)const
{
return val < s.val ;
}
}qe[maxn];
LL xt[101][maxn] ;
int n ,a[maxn] ;
LL dp[maxn][101] ;
void insert(int id,int x,int add)
{
while( x <= n )
{
xt[id][x]+= add;
if(xt[id][x] >= mod) xt[id][x] -= mod;
x += (x&-x) ;
}
}
LL sum(int id,int x)
{
LL ans=0;
while(x >0)
{
ans += xt[id][x] ;
if(ans>=mod) ans -= mod;
x -= (x&-x) ;
}
return ans;
}
int main()
{
int m,i,j ;
while( scanf("%d%d",&n,&m) != EOF)
{
for( i = 1 ; i <= n ;i++)
{
scanf("%I64d",&qe[i].val) ;
qe[i].id= i;
}
sort(qe+1,qe+1+n) ;
j = 1 ;
a[qe[1].id] = j ;
for( i = 2 ; i <= n ;i++)
{
if(qe[i].val==qe[i-1].val) a[qe[i].id]=j ;
else a[qe[i].id] = ++j;
}
memset(xt,0,sizeof(xt)) ;
memset(dp,0,sizeof(dp)) ;
LL ans=0;
for(i = 1 ; i <= n ;i++)
{
dp[i][1] = 1 ;
for( j = 2 ; j <= m && j <= i ;j++)
{
dp[i][j] = sum(j-1,a[i]-1) ;
}
ans = (ans+dp[i][m])%mod;
for( j = 1 ; j <= m && j <= i;j++)
{
insert(j,a[i],dp[i][j]) ;
}
}
cout << ans << endl;
}
return 0 ;
}
原文:http://www.cnblogs.com/20120125llcai/p/3961621.html