sequence2
Accepts: 93
Submissions: 358
Time Limit: 2000/1000 MS (Java/Others)
Memory Limit: 65536/65536 K (Java/Others)
问题描述
给定长度为n的序列bi,求有多少长度为k的本质不同的上升子序列。 设该序列位置为a1,a2...ak一个序列为上升子序列,当且仅当a1<a2<...<ak且ba1<ba2<...<bak。 本质不同当且仅当两个序列a和A存在一个i使得ai≠Ai。
输入描述
若干组数据(大概5组)。 每组数据第一行两个整数n(1≤n≤100),k(1≤k≤n)。 接下来一行n个整数bi(0≤bi≤109)。
输出描述
对于每组的每个询问,输出一行。
输入样例
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)
*/