MIS

来源:互联网 发布:网络高清图片 编辑:程序博客网 时间:2024/04/29 06:18

题目描述 长度为m的递增子序列(M length IncreaseSubsequence),称为MIS。
求长度为n的序列,有多少个MIS。子序列不需要在原序列中不需要连续,但要保证相对位置。 输入
第一行两个整数n和m第二行n个整数,表示一个序列。 输出 输出MIS的个数,结果对20140921取余。
对于100%的数据,n的范围[1,10000],m的的范围[1,100],序列中的元素范围[1,109];

题目分析: 关键字:DP,线段树优化(dp离散线段树) 首先,可以由本题想到LIS,从而想到DP,给出三要素
定义:dp[i][j]表示以i为结尾前面达到长度为j时拥有的方案数
初始化:for i to n dp[i][1]=1;
状态转移方程:dp[i][j]={∑dp[k][j-1] | k < i && A[k] < A[i]}

暴力:         for(int i=1;i<=n;i++) dp[i][1]=1;for(int i=1;i<=n;i++)   for(int j=2;j<=m;j++)     for(int k=i-1;k>=1;k--) if(A[k]<A[i]) dp[i][j]+=dp[k][j-1];

优化:观察,发现对于每一对(i,j)而言,就是把所有下标小于i,权值小于自己的dp[k][j-1]相加
若是权值有了单调性,那么第一个权值满足后,之后所有的都满足,区间查询,就可以想到线段树了。剩下就是下标的问题,但这其实是不需要考虑的,因为我们建了一颗权值线段树后,初始值是0,而下标小的一定先被更新到,那么下标大的就不会对其产生影响,每次查询之后修改,就一定能保证跟新次序是对的(注意一些小细节,就可以了);最后题目复杂度为O(n*m*log(n));
注:代码实现能力是练出来的,一定要敲一遍
WA:
1. 线段树中update中把x当成了pos用(变量混用)
2. 以i为结尾长度为1的个数显然为1,所以自己直接更新在线段树上,dp值没更新(注意关联变量之间的互相更新。

#include<bits/stdc++.h>using namespace std;#define N 10005#define M 105#define MOD 20140921#define FOR(i,a,b) for(int i=(a);i<=(b);i++)#define DOR(i,a,b) for(int i=(a);i>=(b);i--)int A[N],dp[N][M],T[N],tmp[N];int n,m,ans;void add(int &a,int b){    a+=b%MOD;    if(a>=MOD) a-=MOD;}struct Segment{    struct{        int L,R,sum;    }tree[N<<2];    void Up(int p){tree[p].sum=(tree[p<<1].sum+tree[p<<1|1].sum)%MOD;}    void build(int p,int L,int R){        tree[p].L=L,tree[p].R=R;        if(L==R){            tree[p].sum=0;            return;        }        int mid=(L+R)>>1;        build(p<<1,L,mid);        build(p<<1|1,mid+1,R);        Up(p);    }    int query(int p,int L,int R){        if(tree[p].L==L&&tree[p].R==R){            return tree[p].sum;        }        int mid=(tree[p].L+tree[p].R)>>1;        if(R<=mid) return query(p<<1,L,R)%MOD;        else if(L>mid) return query(p<<1|1,L,R)%MOD;        else return (query(p<<1,L,mid)+query(p<<1|1,mid+1,R))%MOD;    }    void update(int p,int pos,int x){        if(tree[p].L==tree[p].R){            add(tree[p].sum,x);            return;        }        int mid=(tree[p].L+tree[p].R)>>1;        if(pos<=mid) update(p<<1,pos,x);        else update(p<<1|1,pos,x);        Up(p);    }}tree[M];int main(){    scanf("%d %d",&n,&m);    FOR(i,1,n) scanf("%d",&A[i]),tmp[i]=A[i];    sort(tmp+1,tmp+1+n);    int tmp_len=unique(tmp+1,tmp+1+n)-tmp-1;    FOR(i,1,m) tree[i].build(1,1,tmp_len);    FOR(i,1,n){        int pos=lower_bound(tmp+1,tmp+tmp_len+1,A[i])-tmp;        tree[1].update(1,pos,1);        dp[i][1]=1;        if(pos>1) FOR(j,2,m){            dp[i][j]=tree[j-1].query(1,1,pos-1)%MOD;            tree[j].update(1,pos,dp[i][j]);        }    }    FOR(i,1,n) add(ans,dp[i][m]);    printf("%d\n",ans%MOD);    return 0;}
原创粉丝点击