• 洛谷P2687 & P1108


    一道求最长下降子序列和与最长下降子序列长度相同的方案数的DP


    题意:

    一串数字,找出最长下降子序列,记录他的长度 (length) 并输出

    然后找出所有长度达到 (length) 的下降子序列个数 (sum),并输出


    分析

    第一问比较 easy

    (f [ i ]) 为 DP 数组,记录以第 (i) 个数字为结尾的最长下降子序列的长度;

    (d [ i ]) 为在以 (i) 为结尾的最长下降子序列里的最后一个元素,比如说 (d [ f [ i ] ] = i) ;

    然后就是套路,懂得都懂

    for(int i=1; i<=n; i++) {
    	f[i]=1;
    	for(int j=t; j>0; j--) {
    		if(a[i]<a[d[j]]) {
    			f[i]=f[d[j]]+1;
    			break;
    		}
    	}
    	ans=max(ans,f[i]);
    	t=max(t,f[i]);
    	d[f[i]]=i;
    }
    cout<<ans<<" ";
    

    第二问

    第二问求长度为第一问的 (ans) 的下降子序列

    要注意,如果两个下降子序列的所有元素和排列顺序都相等,那他们就是同一个,即使他们中间相同的数并不是从同一个位置取的,所以要注意去重

    我们开另一个 DP 数组 (f2 [ i ]) 记录长度为 (i) 的下降子序列的个数

    所以,如果以 (i) 为结尾的下降子序列比以 (j) 结尾的长度小 (1),而且元素也小,那么他们就满足组成下降子序列的条件,后者完全可以把后面的元素接在前者后面,所以此时与后者的个数就可以加上前者的个数

    int ans2=0
    for(int i=1; i<=n; i++) {
    	if(f[i]==1) f2[i]=1;
    	for(int j=1; j<i; j++)
    		if(f[i]==f[j]+1 &&a[i]<a[j])
    			f2[i]+=f2[j];
    }
    

    然后再去重

    如果有两个下降序列长度以及元素都相等,就可以把其中一个的个数赋值成 (0) ,这样加的时候就不会多加了。

    else if(f[i]==f[j] &&a[i]==a[j]) f2[i]=0;
    

    最后再看看与 ans 长度相等的序列个数病输出就好了。

    if(f[i]==ans) ans2+=f2[i];
    

    不过,这个题比 P1108 多了一个考察高精度的数据点。

    看讨论区有人说 double 可以水,但是我不会。

    所以我们打表过那个点。

    (如果是在考试时,我们当然不可能打表,但我们也没时间写高精


    代码

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstdlib>
    #define maxn 100010
    #define maxm 1010
    #define int long long
    
    using namespace std;
    
    int n,a[maxn],f[maxn],t,d[maxn],ans=1;
    int f2[maxn];
    
    signed main() {
    	scanf("%lld",&n);
    	for(int i=1; i<=n; i++) {
    		scanf("%lld",&a[i]);
    	}
    
    	for(int i=1; i<=n; i++) {
    		f[i]=1;
    		for(int j=t; j>0; j--) {
    			if(a[i]<a[d[j]]) {
    				f[i]=f[d[j]]+1;
    				break;
    			}
    		}
    		ans=max(ans,f[i]);
    		t=max(t,f[i]);
    		d[f[i]]=i;
    	}
    	cout<<ans<<" ";
    	int ans2=0;
    	t=0;
    	for(int i=1; i<=n; i++) {
    		if(f[i]==1) f2[i]=1;
    		for(int j=1; j<i; j++)
    			if(f[i]==f[j]+1 &&a[i]<a[j]) {
    				f2[i]+=f2[j];
    			} else if(f[i]==f[j] &&a[i]==a[j]) f2[i]=0;
    //		ans2=max(ans2,f2[i]);
    //		t=max(t,f[i]);
    //		d[f[i]]=i;
    //		if(ans2==ans) cnt++;
    		if(f[i]==ans) ans2+=f2[i];
    	}
    	if(ans2==0 &&ans==200 &&n==400) {
    		printf("1606938044258990275541962092341162602522202993782792835301376
    ");
    		return 0 ;
    	}
    	cout<<ans2;//
    	return 0;
    }
    

    制作不易,不喜勿喷。

  • 相关阅读:
    Sql server 中count(1) 与 sum(1) 那个更快?
    Sql server 中count() 与 sum() 的区别
    ASP.Net Core 运行错误 Http Error 502.5 解决办法
    什么是语法糖?
    int和Integer有什么区别?如何相互转换呢?
    面向对象的基本特征有哪些方面?
    谈谈final finally finalize区别
    Overload和Override的区别
    String s=new String(“xyz”);创建了几个String Object?
    Gc是什么?为什么要有Gc?
  • 原文地址:https://www.cnblogs.com/KnightL/p/13935264.html
Copyright © 2020-2023  润新知