天天看點

C. Subsequences(樹狀數組優化的dp)

記錄一下,雖然挺好想的,但是樹狀數組優化

d

p

dp

dp還是第一次

,

n

2

k

普通轉移應該都知道,是n^2k的大暴力

普通轉移應該都知道,是n2k的大暴力

for(int i=1;i<=n;i++)
for(int j=1;j<i;j++)
{
	if(a[i]<=a[j] )	continue;
	for(int q=1;q<=k;q++)
		dp[i][q]+=dp[j][q-1];
}	
           

[

1

i

]

每次去[1,i-1]找轉移對象太耗時間了

每次去[1,i−1]找轉移對象太耗時間了

a

我們不就是需要那些比a[i]小的答案嗎

我們不就是需要那些比a[i]小的答案嗎

/*
1 2 3 4 5
找到遞增的長k+1的子序列個數 
dp[i][len]表示以i結尾長len的方案 
*/
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=1e5+10;
int n,k,a[maxn],dp[maxn][12];
class like_tree_array
{
	private:
		int sumn[maxn];
		int lowbit(int x){
			return x&(-x);
		}
	public:
		void add(int x,int k){
			for(;x<=n;x+=lowbit(x))	sumn[x]+=k;
		}
		int ask(int x){
			int ans=0;
			for(;x;x-=lowbit(x))	ans+=sumn[x];
			return ans;
		}
}mp[12];
signed main()
{
	cin >> n >> k;
	for(int i=1;i<=n;i++)	cin >> a[i];
	for(int i=1;i<=n;i++)
	for(int j=k+1;j>=1;j--)//倒序枚舉,因為下面有插入操作,類似01背包 
	{
		if( j==1 )	dp[i][j]=1;
		else dp[i][j]=mp[j-1].ask( a[i] );//小于a[i]的都行 
		mp[j].add( a[i],dp[i][j] );
	}
	int ans=0;
	for(int i=k+1;i<=n;i++)	ans+=dp[i][k+1];
	cout << ans;
}
           

繼續閱讀