cf597 C. Subsequences(dp+树状数组)
题意:
给定长为 \(n\) 的数组,元素两两不同。求长度为 \(k+1\) 的上升子列的数量。
\(1\le n\le 10^5,0\le k \le 10, 1\le a_i\le n\) ,保证答案 \(\le 8e18\)
思路:
\(f[i][j]\) 表示以 \(a_i\) 结尾且长度为 \(j\) 的上升子列的数量。目标:\(\sum \limits _{1\le i\le n} f[i][k+1]\)
\(f[i][j] = \sum\limits _{x<i且a_x<a_i} f[x][j-1]\) ,即上一层(\(j-1\))的 \(a_i\) 前面的比 \(a_i\) 小的状态之和,复杂度 \(O(kn^2)\) 。在值域上开11个树状数组, \(tr[j]\) 记录每一层。注意加一个算一个,只算 \(i\) 前面的。
const int N = 1e5 + 5;
int n, k, a[N];
ll f[N][13];
ll tr[13][N];
int lowbit(int x) {return x&-x; }
void add(ll *tr, int p, ll x) {for(;p<=n;p+=lowbit(p))tr[p]+=x; }
ll ask(ll *tr, int p) {ll s=0;for(;p;p-=lowbit(p))s+=tr[p];return s; }
signed main()
{
    cin >> n >> k;
    for(int i = 1; i <= n; i++) cin >> a[i];
    for(int i = 1; i <= n; i++) f[i][1] = 1;
    for(int i = 2; i <= k + 1; i++)
        for(int j = 1; j <= n; j++)
            add(tr[i-1], a[j], f[j][i-1]),
            f[j][i] = ask(tr[i-1], a[j]-1);
    ll ans = 0;
    for(int i = 1; i <= n; i++) ans += f[i][k+1];
    cout << ans;
}
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号