【HDU5568 BestCoder Round 63 (div1)A】【DP java高精度】sequence2 长度恰好为m的LIS数

sequence2

 
 Accepts: 93
 
 Submissions: 358
 Time Limit: 2000/1000 MS (Java/Others)
 
 Memory Limit: 65536/65536 K (Java/Others)
问题描述
给定长度为nn的序列b_ibi,求有多少长度为kk的本质不同的上升子序列。
设该序列位置为a_1, a_2 ... a_ka1,a2...ak一个序列为上升子序列,当且仅当a_1 < a_2 < ... < a_ka1<a2<...<akb_{a_1} < b_{a_2} < ... < b{a_k}ba1<ba2<...<bak。
本质不同当且仅当两个序列aaAA存在一个ii使得a_i \neq A_iaiAi
输入描述
若干组数据(大概55组)。
每组数据第一行两个整数n(1 \leq n \leq 100), k(1 \leq k \leq n)n(1n100),k(1kn)。
接下来一行nn个整数b_i(0 \leq b_i \leq 10^{9})bi(0bi109)
输出描述
对于每组的每个询问,输出一行。
输入样例
3 2
1 2 2
3 2
1 2 3
输出样例
2
3


import java.util.*;
import java.math.*;
public class Main 
{
	final static int N=(int)105;
	public static int a[]=new int[N];
	public static int n;
	public static void main(String[] args) 
	{
		BigInteger f[][]=new BigInteger[N][N];	
		Scanner cin=new Scanner(System.in);
		BigInteger zero=BigInteger.valueOf(0);
		BigInteger one=BigInteger.valueOf(1);
		while(cin.hasNext())
		{
			int n=cin.nextInt();
			int m=cin.nextInt();
			for(int i=1;i<=n;i++)a[i]=cin.nextInt();
			for(int i=0;i<=n;i++)
			{
				for(int j=0;j<=m;j++)f[i][j]=zero;
			}
			BigInteger ans=zero;
			for(int i=1;i<=n;i++)
			{
				f[i][1]=one;
				int top=Math.min(i,m);
				for(int j=1;j<i;j++)if(a[j]<a[i])
				{
					int topp=Math.min(top,j+1);
					for(int k=2;k<=topp;k++)
					{
						f[i][k]=f[i][k].add(f[j][k-1]);
					}
				}
				ans=ans.add(f[i][m]);
			}
			System.out.println(ans);
		}
	}
}
/*
【trick&&吐槽】
1,如果遇到n=50,m=50,数列呈现{11 22 33 44 55 66 ……}这样的数据,答案显然是2^50。
如果n=50,m=30,答案是2^30*C(50,30),这个肯定爆掉了LL。于是要同高精度。
2,java的数组一定要养成for循环初始化的好习惯。

【题意】
给你一个数组a[],元素个数最多为n(100),让你求出a[]有多少个长度恰好为m的单调上升子序列。

【类型】
DP java大数

【分析】
数据组数不多,且n只有100,于是我们只需要想一个O(n^3)时间复杂度的算法,就可以AC这道题。
用f[i][j]表示最后一位位置严格为i,单调上升子序列长度为j的方案数。
那么肯定首先有f[i][1]=1,
然后答案是∑f[i][k],
至于状态转移方程,则是:f[i][k]=∑f[j][k-1],j<i且a[j]<a[i]。
这样这道题就做完啦~

【时间复杂度&&优化】
O(Tn^3)

*/


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值