其他分享
首页 > 其他分享> > 1034 小魂和他的数列 dp 树状数组 最长的递增序列数

1034 小魂和他的数列 dp 树状数组 最长的递增序列数

作者:互联网

 链接:https://ac.nowcoder.com/acm/contest/26896/1034
来源:牛客网

题目描述

一天,小魂正和一个数列玩得不亦乐乎。
小魂的数列一共有n个元素,第i个数为Ai
他发现,这个数列的一些子序列中的元素是严格递增的。
他想知道,这个数列一共有多少个长度为K的子序列是严格递增的。
请你帮帮他,答案对998244353取模。 对于100%的数据,1≤ n ≤ 500,000,2≤ K ≤ 10,1≤ Ai ≤ 109

输入描述:

第一行包含两个整数n,K,表示数列元素的个数和子序列的长度。
第二行包含n个整数,表示小魂的数列。

输出描述:

一行一个整数,表示长度为K的严格递增子序列的个数对998244353取模的值。
示例1

输入

复制
5 3
2 3 3 5 1

输出

复制
2

说明

两个子序列分别是2 3 3 5 1和2 3 3 5 1。

分析

dp+树状数组

题目要求最长的递增序列。

很容易想到dp

设dp[i][j]为到 i 点,长度为 j 的序列

dp[i][j] = (a[k] < a[i]) * dp[k][j-1]

但是这种做法是n^3,1e5下明显tle

观察可以知道,如果先对原数列按照从小到大的顺序排序,

遍历到i,i前面的所有k的情况都已经处理好了,那就可以直接前缀和,但是由于坐标是乱的,所以要用树状数组处理到了当前 i 坐标,长度是j ,前面 [1,i] 有多少个坐标,长度是j - 1已经被选上了

有二维考虑二维树状数组。

同时,枚举到当前i ,长度是1的位置每次循环完 k 从K 到 2 ,都要 + 1

sum(i,j) 表示长度为j,在第i个位置前面有多少满足条件的情况,累加起来即可

这里要特殊判断一下,假如数组上有两个值是一样的,如果直接前缀和如果后面的数后放进来,会导致两个一样的数被累加,但这明显不满足a[k]<a[i]。

所以如果是一样的数,排序的时候先计算位置高的数,防止计算到它。

另外长度k 要从大到小计算,如果从小到大,在同一个i 位置会滚动加上对应位置和长度的值。

 

//-------------------------代码----------------------------

//#define int ll
const int N = 5e5+10,mod = 998244353;
int n,k;

struct node {
    int v,id;
    bool operator<(const node x) const {
        if(v == x.v) return id > x.id;//值相等,位置大的先?????????
        return v < x.v;
    }
} w[N];
int a[N][11];


//a[i][j] += (a[k] < a[i]) * a[k][j-1];
//只需要把第一个数到第i个数的所有满足情况的都加起来
void add(int i,int j,int x) {
    for(;i<=n;i+=lowbit(i)) {
        a[i][j] = (a[i][j] + x) % mod;//在a[i][j] 位置 加上权值
    }
}

int sum(int i,int j) {
    int res = 0;
    for(;i;i-=lowbit(i)) {
        res =(res + a[i][j]) % mod;
    } return res;
}

void solve()
{
//    cin>>n>>m;
    cin>>n>>k;
    fo(i,1,n) cin>>w[i].v,w[i].id = i;
    sort(w+1,w+1+n);
    fo(i,1,n) {
        of(j,k,2)
            add(w[i].id,j,sum(w[i].id,j-1));
        add(w[i].id,1,1);//递增序列为1的,肯定只产生一个贡献值
    }
    cout<<sum(n,k)<<endl;
}
void main_init() {}
signed main(){
    AC();clapping();TLE;
    cout<<fixed<<setprecision(12);
    main_init();
//  while(cin>>n,n)
//  while(cin>>n>>m,n,m)
//    int t;cin>>t;while(t -- )
    solve();
//    {solve(); }
    return 0;
}

/*样例区


*/

//------------------------------------------------------------

 

标签:数列,int,小魂,1034,序列,长度,id,dp
来源: https://www.cnblogs.com/er007/p/16583105.html