zoukankan      html  css  js  c++  java
  • 洛谷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;
    }
    

    制作不易,不喜勿喷。

  • 相关阅读:
    ubuntu远程windows桌面
    spring boot 给返回值加状态 BaseData
    spring boot 拦截异常 统一处理
    IntelliJ IDEA spring boot 远程Ddbug调试
    IntelliJ IDEA 常用插件
    spring boot 请求地址带有.json 兼容处理
    spring boot 接口返回值去掉为null的字段
    spring boot 集成disconf
    Spring boot 自定义拦截器
    Linux下安装MySQL
  • 原文地址:https://www.cnblogs.com/KnightL/p/13935264.html
Copyright © 2011-2022 走看看