• 51nod 1376: 最长递增子序列的数量(二维偏序+cdq分治)


    www.cnblogs.com/shaokele/


    1376 最长递增子序列的数量##

      Time Limit: 1 Sec   Memory Limit: 128MB
      分值: 160        难度:6级算法题

    Description###

      数组A包含N个整数(可能包含相同的值)。设S为A的子序列且S中的元素是递增的,则S为A的递增子序列。如果S的长度是所有递增子序列中最长的,则称S为A的最长递增子序列(LIS)。A的LIS可能有很多个。例如A为:{1 3 2 0 4},1 3 4,1 2 4均为A的LIS。给出数组A,求A的LIS有多少个。由于数量很大,输出Mod 1000000007的结果即可。相同的数字在不同的位置,算作不同的,例如 {1 1 2} 答案为2。

    Input###

      第1行:1个数N,表示数组的长度。(1 <= N <= 50000)
      第2 - N + 1行:每行1个数A[i],表示数组的元素(0 <= A[i] <= 10^9)

    Output###

      输出最长递增子序列的数量Mod 1000000007。

    Sample Input###

      5
      1
      3
      2
      0
      4

    Sample Output###

      2

    题目地址: 51nod 1376: 最长递增子序列的数量####

    题目大意: 求最长上升子序列的个数####

    www.cnblogs.com/shaokele/


    题解:####

      显然这道题目有很多做法 (知乎)
      然而这里只做cdq分治
      LIS其实是一个二维偏序问题(下标和值)
      分治的套路:
      第一维排序,第二维分治
      1. 先递归求解区间左半边
      2. 用左边的值更新右边,相当于处理跨越区间中点的情况
      3. 递归求解区间右半边
      

    //by:知乎 李贝瑀
    
    bool cmp(int i, int j) { return a[i] != a[j]? a[i] < a[j]: i > j; }
    
    void cdq(int l, int r)
    {
            if (l == r) {
                    if (!f[l]) f[l] = 1;
                    return;
            }
            int mid = (l + r) >> 1;
            cdq(l, mid);
            for (int i = l; i <= r; ++i) id[i] = i;
            sort(id + l, id + r + 1, cmp);
            int len = 0;
            for (int i = l; i <= r; ++i) {
                    if (id[i] <= mid) len = max(len, f[id[i]]);
                    else f[id[i]] = max(f[id[i]], len + 1);
            }
            // code
            cdq(mid + 1, r);
    }
    

      上面这个写法其实是 (O(Nlog^2N)) 的,因为对id排序时调用了sort,可以改成归并排序

      对于求解方案数,只需要在注释的地方加上统计的代码
      过程和前面基本类似,能理解的话很容易写出来


    AC代码

    #include <cstdio> 
    #include <algorithm>
    #define mp make_pair
    #define pr pair<int,int>
    using namespace std;
    const int N=50005,mo=1000000007;
    int n;
    int a[N],id[N];
    pr f[N];
    bool cmp(int x,int y){
    	if(a[x]!=a[y])return a[x]<a[y];
    	return x>y;
    }
    pr Max(pr a,pr b){
    	if(a.first>b.first)return a;
    	if(a.first<b.first)return b;
    	if((a.second+=b.second)>=mo)
    		a.second-=mo;
    	return a;
    }
    void cdq(int l,int r){
    	if(l==r)return;
    	int mid=(l+r)/2;
    	cdq(l,mid);
    	for(int i=l;i<=r;i++)id[i]=i;
    	sort(id+l,id+r+1,cmp);
    	pr mx=mp(0,0);
    	for(int i=l;i<=r;i++){
    		int k=id[i];
    		if(k<=mid)mx=Max(mx,f[k]);
    		else{
    			pr now=mx;
    			now.first++;
    			f[k]=Max(f[k],now);
    		}
    	}
    	cdq(mid+1,r);
    }
    int main(){
    	scanf("%d",&n);
    	for(int i=1;i<=n;i++)
    		scanf("%d",&a[i]);
    	for(int i=1;i<=n;i++)
    		f[i]=mp(1,1);
    	cdq(1,n);
    	pr ans=mp(0,0);
    	for(int i=1;i<=n;i++)
    		ans=Max(ans,f[i]);
    	printf("%d
    ",ans.second);
    	return 0;
    }
    
  • 相关阅读:
    年轻人的第一个 Spring Boot 应用,太爽了!
    面试问我 Java 逃逸分析,瞬间被秒杀了。。
    Spring Boot 配置文件 bootstrap vs application 到底有什么区别?
    坑爹的 Java 可变参数,把我整得够惨。。
    6月来了,Java还是第一!
    Eclipse 最常用的 10 组快捷键,个个牛逼!
    Spring Cloud Eureka 自我保护机制实战分析
    今天是 Java 诞生日,Java 24 岁了!
    厉害了,Dubbo 正式毕业!
    Spring Boot 2.1.5 正式发布,1.5.x 即将结束使命!
  • 原文地址:https://www.cnblogs.com/shaokele/p/9061817.html
Copyright © 2020-2023  润新知