【动态规划+高精度】mr360-定长不下降子序列

【题目大意】

韵哲君发现自己的面前有一行数字,当她正在琢磨应该干什么的时候,这时候,陈凡老师从天而降,走到了韵哲君的身边,低下头,对她耳语了几句,然后飘然而去。

陈凡老师说了什么呢,陈凡老师对韵哲君说了这些话:“还记得我传授给你的不下降子序列吗?你现在只要找出一定长度的不下降子序列的种数,你就完成任务了。”

你也来做做这个活动吧?

输入格式 Input Format

第一行有两个整数N(0<N<=200),M(0<M<=20);

N表示给出多少个整数,M表示给出的定长;

第二行有N个整数,对于每个数字(-10000<=T[i]<=10000)。

输出格式 Output Format

输出一个整数,在给出的数列中定长不下降子序列的种数。

样例输入 Sample Input

10 5

1 2 3 4 5 6 7 8 9 10

样例输出 Sample Output

252

时间限制 Time Limitation

2s(对于高精度版)

【思路】

动态规划,设置数组f[i][j]表示以第i个数字为末位,长度为j的不下降子序列种类数。设置三重循环,第一重表示以第i个数字为末位,第二重j表示当前要取的不下降子序列长度,第三重k枚举这个不下降子序列的倒数第二个数字。如果a[i]≥a[k],则f[i][j]=f[i][j]+f[k][j-1]。

要注意的是,最后输出结果不是f[n][m],而是所有f[i][m]的累加!我因为这个一开始错了好久…

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<cmath>
 5 using namespace std;
 6 const int MAXN=200+50;
 7 struct node
 8 {
 9     int num[100];
10     int len;
11 };
12 int n,m;
13 int a[MAXN];
14 node f[MAXN][MAXN/10];
15
16 void init()
17 {
18     scanf("%d%d",&n,&m);
19     for (int i=0;i<n;i++) scanf("%d",&a[i]);
20     for (int i=0;i<n;i++)
21         for (int j=1;j<=m;j++)
22         {
23             memset(f[i][j].num,0,sizeof(f[i][j].num));
24             if (j==1)
25             {
26                 f[i][j].num[0]=1;
27                 f[i][j].len=1;
28             }
29             else f[i][j].len=0;
30         }
31 }
32
33 void doadd(int a[100],int b[100],int &la,int lb)
34 {
35     int leng=max(la,lb);
36     int temp[100];
37     memset(temp,0,sizeof(temp));
38     for (int p=0;p<leng;p++)
39     {
40         temp[p]+=a[p]+b[p];
41         /*由于是先进行进位的,这里不是将a[p]+b[p]赋值,而是累加在temp[p]上面*/
42         temp[p+1]=temp[p]/10;
43         temp[p]=temp[p]%10;
44     }
45     if (temp[leng]>0) leng++;
46     la=leng;
47     for (int p=0;p<leng;p++) a[p]=temp[p];
48 }
49
50 void dp()
51 {
52     for (int i=1;i<n;i++)/*以第i个数为末位*/
53         for (int j=2;j<=min(i+1,m);j++)/*长度为j,只需取到i+1和m中较小的一个即可*/
54             for (int k=j-2;k<i;k++)/*前一个数字为k,只需从能够取到j-1长度的那一位,即j-2开始*/
55                 if (a[i]>=a[k])
56                     doadd(f[i][j].num,f[k][j-1].num,f[i][j].len,f[k][j-1].len);/*f[i][j].num+=f[k][j-1].num*/
57 }
58
59 void print()
60 {
61     int ans[100];
62     memset(ans,0,sizeof(ans));
63     int lans=0;
64
65     for (int i=m-1;i<n;i++) doadd(ans,f[i][m].num,lans,f[i][m].len);
66     /*不是直接输出f[n-1][m],而是要将f[i][m]进行累加*/
67     for (int i=lans-1;i>=0;i--) cout<<ans[i];cout<<endl;
68 }
69
70 int main()
71 {
72     freopen("mr360.in1","r",stdin);
73     freopen("mr360.ou1","w",stdout);
74     init();
75     dp();
76     print();
77     return 0;
78 }
时间: 2024-08-28 12:08:09

【动态规划+高精度】mr360-定长不下降子序列的相关文章

【网络流24题】最长不下降子序列(最大流,动态规划)

[网络流24题]最长不下降子序列(最大流,动态规划) 题面 Cogs 题解 很有趣的一道题目 尽管我自己还是有一些懵逼 第一问,直接大力DP一下,不解释了 第二问,考虑到一个长度为ans的子序列的开头 他的dp值一定等于ans, 所以,如果一个点的dp值为ans,就从源点连过去,容量为1 因为每个数只能用一次,因此拆点 自己向自己的新点连容量为1的边 一个子序列的结束的位置其dp值必定为1 所以从dp值为1的新点向汇点连边,容量为1 接下来考虑点与点之间的关系 如果dp[i]=dp[j]+1 并

动态规划——最长不下降子序列(LIS)

最长不降子序列是这样一个问题: 下面介绍动态规划的做法. 令 dp[i] 表示以 A[i] 结尾的最长不下降序列长度.这样对 A[i] 来说就会有两种可能: 如果存在 A[i] 之前的元素 A[j] (j<i),使得 A[j]≤A[i] 且 dp[j]+1>dp[i],那么就把 A[i] 跟在以 A[j] 结尾的 LIS 后面,形成一条更长的不下降子序列(令 dp[i]=dp[j]+1). 如果 A[i] 之前的元素都比 A[i] 大,那么 A[i] 就只好自己形成一条 LIS,但是长度为 1

P2766 最长不下降子序列问题 网络流

link:https://www.luogu.org/problemnew/show/P2766 题意 给定正整数序列x1,...,xn . (1)计算其最长不下降子序列的长度s. (2)计算从给定的序列中最多可取出多少个长度为s的不下降子序列. (3)如果允许在取出的序列中多次使用x1和xn,则从给定序列中最多可取出多少个长度为s的不下降子序列. 设计有效算法完成(1)(2)(3)提出的计算任务. 思路 题解来自网络流24题: [问题分析] 第一问是LIS,动态规划求解,第二问和第三问用网络最

swust oj 585--倒金字塔(LIS最长不下降子序列)

题目链接:http://acm.swust.edu.cn/problem/585/ Time limit(ms): 3000 Memory limit(kb): 65535 SWUST国的一支科学考察队到达了举世闻名的古埃及金字塔. 关于金字塔的建造一直是一个未解之谜, 有着“西方史学之父”之称的希罗多德认为,金字塔的建造是人力和牲畜,花费20 年时间从西奈半岛挖掘天然的石头运送到埃及堆砌而成.也有不少人认为是外星人修建的.人们发现胡夫金字塔的经线把地球分成东.西两个半球,它们的陆地面积是相等的

最长不下降子序列nlogn算法详解

今天花了很长时间终于弄懂了这个算法……毕竟找一个好的讲解真的太难了,所以励志我要自己写一个好的讲解QAQ 这篇文章是在懂了这个问题n^2解决方案的基础上学习. 解决的问题:给定一个序列,求最长不下降子序列的长度(nlogn的算法没法求出具体的序列是什么) 定义:a[1..n]为原始序列,d[k]表示长度为k的不下降子序列末尾元素的最小值,len表示当前已知的最长子序列的长度. 初始化:d[1]=a[1]; len=1; (0个元素的时候特判一下) 现在我们已知最长的不下降子序列长度为1,末尾元素

tyvj 1049 最长不下降子序列 n^2/nlogn

P1049 最长不下降子序列 时间: 1000ms / 空间: 131072KiB / Java类名: Main 描述 求最长不下降子序列的长度 输入格式 第一行为n,表示n个数第二行n个数 输出格式 最长不下降子序列的长度 测试样例1 输入 3 1 2 3 输出 3 备注 N小于5000for each num <=maxint 题意:中文题意 题解:不下降也就是>= n^n  dp[i] 表示前i个数的最长不下降子序列的长度 1 /*****************************

hdu 1160 FatMouse&#39;s Speed(最长不下降子序列+输出路径)

题意: FatMouse believes that the fatter a mouse is, the faster it runs. To disprove this, you want to take the data on a collection of mice and put as large a subset of this data as possible into a sequence so that the weights are increasing, but the s

【DP】最长不下降子序列问题(二分)

Description 给你一个长度为n的整数序列,按从左往右的顺序选择尽量多的数字并且满足这些数字不下降. Thinking 朴素dp算法:F[i]表示到第i位为止的最长不下降子序列长度 F[i]=max(F[j])+1,其中(j<i且a[j]<=a[i]) 时间复杂度:O(n2) 考虑维护一个队列g,用g[i]表示长度为i的最长不下降子序列结尾的最小值.根据g[i]的单调性,可以用二分查找的方法快速找到以当前数a[i]结尾的最长不下降子序列. Code 1 #include<cstd

O(n log n)求最长上升子序列与最长不下降子序列

考虑dp(i)表示新上升子序列第i位数值的最小值.由于dp数组是单调的,所以对于每一个数,我们可以二分出它在dp数组中的位置,然后更新就可以了,最终的答案就是dp数组中第一个出现正无穷的位置. 代码非常简单: for(int i=0;i<n;i++)dp[i]=oo; for(int i=0;i<n;i++)*lower_bound(dp,dp+n,A[i])=A[i]; printf("%d\n",(lower_bound(dp,dp+n,oo)-dp)); 如果是最长不