$HDOJ5542\ The\ Battle\ of\ Chibi$ 数据结构优化$DP$

$AcWing$

 

$Description$

 

 

$Sol$

首先显然是是以严格递增子序列的长度为阶段,由于要单调递增,所以还要记录最后一位的数值
$F[i][j]$表示前$i$个数中以$A_i$结尾的长度为j单调递增序列有多少个
$F[i][j]=\sum_{k<i且A_k<A_i}^{ }F[k][j-1]$
注意到,如果没有$A_k<A_i$这个条件我们就可以直接维护前缀和了
有$A_k<A_i$这个条件,可以考虑维护$A_i$为下标,$F[i][j-1]$为值的数组的前缀和
$A_i$的值会过大而不能作为下标,要离散化
但是$i$每增加$1$,这个数组并不像之前那样简单的在数组后面加一个值,而是在不确定的地方修改,这样的话如果再是朴素地维护前缀和也起不到上面优化的作用了
待修改的区间求和问题$???$树状数组$!!!$
也就是说维护一个以$A_i$的离散值为下标,$F[i][j-1]$为值的树状数组就好啦
然后讲下细节(敖丙说了细节决定成败$qwq$).就是初始化是$f[0][0]=1$,但是众所周知树状数组的下标不可以为$0$,所以把整个树状数组往右移一位.
 

$Code$

 1 #include<bits/stdc++.h>
 2 #define il inline
 3 #define Rg register
 4 #define go(i,a,b) for(Rg int i=a;i<=b;i++)
 5 #define yes(i,a,b) for(Rg int i=a;i>=b;i--)
 6 #define mem(a,b) memset(a,b,sizeof(a));
 7 #define int long long
 8 using namespace std;
 9 il int read()
10 {
11     int x=0,y=1;char c=getchar();
12     while(c<'0'||c>'9'){if(c=='-')y=-1;c=getchar();}
13     while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+c-'0';c=getchar();}
14     return x*y;
15 }
16 const int N=1010,mod=(1e9)+7;
17 int T,n,n1,m,as,a[N],b[N],v[N],c[N],f[N][N];
18 il int Find(int x){return find(b+1,b+n1+1,x)-b;}//find(b+1,b+n1+1,x)-b;}
19 il int lowbit(int x){return x&(-x);}
20 il void add(int p,int w){while(p<=n1){c[p]=(c[p]+w)%mod;p+=lowbit(p);}}
21 il int sum(int p){int ret=0;while(p){ret=(ret+c[p])%mod;p-=lowbit(p);}return ret%mod;}
22 main()
23 {
24     T=read();
25     go(TT,1,T)//remember to init
26     {
27         n=read(),m=read();
28         go(i,1,n)a[i]=b[i]=read();
29         sort(b+1,b+n+1);
30         n1=unique(b+1,b+n+1)-(b+1);
31         go(i,1,n){v[i]=Find(a[i]);}
32         f[0][0]=1;
33         go(i,1,m)
34         {
35             mem(c,0);if(i==1)add(1,1);
36             go(j,1,n)f[i][j]=sum(v[j]),add(v[j]+1,f[i-1][j]);
37         }
38         as=0;go(i,1,n)as=(as+f[m][i])%mod;
39         printf("Case #%lld: %lld\n",TT,as);
40     }
41     return 0;
42 }
View Code

 

 

 

posted @ 2019-07-29 15:46  DTTTTTTT  阅读(124)  评论(0编辑  收藏  举报