题目链接 : http://acm.hdu.edu.cn/showproblem.php?pid=5568

题意 :

给一个长度已知的序列, 给一个值k, 问该序列中有多少种长度为k的上升子序列

思路 :

日常读错题..理解成有多少种值不同且长度为k的上升子序列了,

而原意是只要任意两个子序列的下标不同即可

就按官方题解的解法, dp, 用二维数组dp[i][j]位置i的数作为子序列中第j个数的方案数

故遍历序列, 对一个位置i, 它作为序列中第k大的值, 如果在它之前有b[i] > b[j], 那么dp[i][k] += dp[j][k-1]

而且要用大数存放, 随便举个例子, 给出100个数1到100, 给出k=50, 答案即为C(50, 100);

dp代码 :

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream> using namespace std; const int N = 1e2+; #define MAXN 9999
#define MAXSIZE 1010
#define DLEN 4
class BigNum {
private:
int a[]; //可以控制大数的位数
int len;
public:
BigNum() {
len=; //构造函数
memset(a,,sizeof(a));
}
BigNum(const int); //将一个int类型的变量转化成大数
BigNum(const char*); //将一个字符串类型的变量转化为大数
BigNum(const BigNum &); //拷贝构造函数
BigNum &operator=(const BigNum &); //重载赋值运算符,大数之间进行赋值运算
friend istream& operator>>(istream&,BigNum&); //重载输入运算符
friend ostream& operator<<(ostream&,BigNum&); //重载输出运算符
BigNum operator+(const BigNum &)const; //重载加法运算符,两个大数之间的相加运算
BigNum operator-(const BigNum &)const; //重载减法运算符,两个大数之间的相减运算
BigNum operator*(const BigNum &)const; //重载乘法运算符,两个大数之间的相乘运算
BigNum operator/(const int &)const; //重载除法运算符,大数对一个整数进行相除运算
BigNum operator^(const int &)const; //大数的n次方运算
int operator%(const int &)const; //大数对一个int类型的变量进行取模运算
bool operator>(const BigNum &T)const; //大数和另一个大数的大小比较
bool operator>(const int &t)const; //大数和一个int类型的变量的大小比较
void print(); //输出大数
};
BigNum::BigNum(const int b) { //将一个int类型的变量转化为大数
int c,d=b;
len=;
memset(a,,sizeof(a));
while(d>MAXN) {
c=d-(d/(MAXN+))*(MAXN+);
d=d/(MAXN+);
a[len++]=c;
}
a[len++]=d;
}
BigNum::BigNum(const char *s) { //将一个字符串类型的变量转化为大数
int t,k,index,L,i;
memset(a,,sizeof(a));
L=strlen(s);
len=L/DLEN;
if(L%DLEN)len++;
index=;
for(i=L-; i>=; i-=DLEN) {
t=;
k=i-DLEN+;
if(k<)k=;
for(int j=k; j<=i; j++)
t=t*+s[j]-'';
a[index++]=t;
}
}
BigNum::BigNum(const BigNum &T):len(T.len) { //拷贝构造函数
int i;
memset(a,,sizeof(a));
for(i=; i<len; i++)
a[i]=T.a[i];
}
BigNum & BigNum::operator=(const BigNum &n) { //重载赋值运算符,大数之间赋值运算
int i;
len=n.len;
memset(a,,sizeof(a));
for(i=; i<len; i++)
a[i]=n.a[i];
return *this;
}
istream& operator>>(istream &in,BigNum &b) {
char ch[MAXSIZE*];
int i=-;
in>>ch;
int L=strlen(ch);
int count=,sum=;
for(i=L-; i>=;) {
sum=;
int t=;
for(int j=; j<&&i>=; j++,i--,t*=) {
sum+=(ch[i]-'')*t;
}
b.a[count]=sum;
count++;
}
b.len=count++;
return in;
}
ostream& operator<<(ostream& out,BigNum& b) { //重载输出运算符
int i;
cout<<b.a[b.len-];
for(i=b.len-; i>=; i--) {
printf("%04d",b.a[i]);
}
return out;
}
BigNum BigNum::operator+(const BigNum &T)const { //两个大数之间的相加运算
BigNum t(*this);
int i,big;
big=T.len>len?T.len:len;
for(i=; i<big; i++) {
t.a[i]+=T.a[i];
if(t.a[i]>MAXN) {
t.a[i+]++;
t.a[i]-=MAXN+;
}
}
if(t.a[big]!=)
t.len=big+;
else t.len=big;
return t;
}
BigNum BigNum::operator-(const BigNum &T)const { //两个大数之间的相减运算
int i,j,big;
bool flag;
BigNum t1,t2;
if(*this>T) {
t1=*this;
t2=T;
flag=;
} else {
t1=T;
t2=*this;
flag=;
}
big=t1.len;
for(i=; i<big; i++) {
if(t1.a[i]<t2.a[i]) {
j=i+;
while(t1.a[j]==)
j++;
t1.a[j--]--;
while(j>i)
t1.a[j--]+=MAXN;
t1.a[i]+=MAXN+-t2.a[i];
} else t1.a[i]-=t2.a[i];
}
t1.len=big;
while(t1.a[len-]== && t1.len>) {
t1.len--;
big--;
}
if(flag)
t1.a[big-]=-t1.a[big-];
return t1;
}
BigNum BigNum::operator*(const BigNum &T)const { //两个大数之间的相乘
BigNum ret;
int i,j,up;
int temp,temp1;
for(i=; i<len; i++) {
up=;
for(j=; j<T.len; j++) {
temp=a[i]*T.a[j]+ret.a[i+j]+up;
if(temp>MAXN) {
temp1=temp-temp/(MAXN+)*(MAXN+);
up=temp/(MAXN+);
ret.a[i+j]=temp1;
} else {
up=;
ret.a[i+j]=temp;
}
}
if(up!=)
ret.a[i+j]=up;
}
ret.len=i+j;
while(ret.a[ret.len-]== && ret.len>)ret.len--;
return ret;
}
BigNum BigNum::operator/(const int &b)const { //大数对一个整数进行相除运算
BigNum ret;
int i,down=;
for(i=len-; i>=; i--) {
ret.a[i]=(a[i]+down*(MAXN+))/b;
down=a[i]+down*(MAXN+)-ret.a[i]*b;
}
ret.len=len;
while(ret.a[ret.len-]== && ret.len>)
ret.len--;
return ret;
}
int BigNum::operator%(const int &b)const { //大数对一个 int类型的变量进行取模
int i,d=;
for(i=len-; i>=; i--)
d=((d*(MAXN+))%b+a[i])%b;
return d;
}
BigNum BigNum::operator^(const int &n)const { //大数的n次方运算
BigNum t,ret();
int i;
if(n<)exit(-);
if(n==)return ;
if(n==)return *this;
int m=n;
while(m>) {
t=*this;
for(i=; (i<<)<=m; i<<=)
t=t*t;
m-=i;
ret=ret*t;
if(m==)ret=ret*(*this);
}
return ret;
}
bool BigNum::operator>(const BigNum &T)const { //大数和另一个大数的大小比较
int ln;
if(len>T.len)return true;
else if(len==T.len) {
ln=len-;
while(a[ln]==T.a[ln]&&ln>=)
ln--;
if(ln>= && a[ln]>T.a[ln])
return true;
else
return false;
} else
return false;
} bool BigNum::operator>(const int &t)const { //大数和一个int类型的变量的大小比较
BigNum b(t);
return *this>b;
}
void BigNum::print() { //输出大数
int i;
printf("%d",a[len-]);
for(i=len-; i>=; i--)
printf("%04d",a[i]);
printf("\n");
} int a[N];
BigNum dp[N][N]; void Init(int n)
{
for(int i = ; i <= n; i++) {
for(int j = ; j <= n; j++) {
dp[i][j] = ;
}
}
dp[][] = ;
} int main()
{
int n, k; while(scanf("%d %d", &n, &k) != EOF) {
Init(n);
for(int i = ; i <= n; i++) {
scanf("%d", &a[i]);
}
for(int i = ; i <= n; i++) {
for(int k = ; k <= n; k++) {
for(int j = ; j < i; j++) {
if(a[i] > a[j]) {
dp[i][k] = dp[i][k] + dp[j][k-];
}
}
}
}
BigNum ans = ;
for(int i = k; i <= n; i++) {
ans = ans + dp[i][k];
}
ans.print();
} return ;
}

有一种更好的dp方法, 参考其他大牛写的

原来的dp, 复杂度是O(n*n*k)

而这一种用到树状数组, 可以做到O(n*logn*k)

先对原数组记录下标和值, 按值进行升序排序

之后对于第num个数从1到k, 遍历每一个数a[j]

在这个数的原位置插入dp[j][num], 并用dp[j][num]加上满足以下条件的数目总和

1. 位置在 a[j] 原位置的前面 (这个通过树状数组完成了)

2. 值比 a[j] 代表的值小 (这点通过排序完成了)

代码 :

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream> using namespace std; const int N = 1e2+; #define MAXN 9999
#define MAXSIZE 1010
#define DLEN 4
class BigNum {
private:
int a[]; //可以控制大数的位数
int len;
public:
BigNum() {
len=; //构造函数
memset(a,,sizeof(a));
}
BigNum(const int); //将一个int类型的变量转化成大数
BigNum(const char*); //将一个字符串类型的变量转化为大数
BigNum(const BigNum &); //拷贝构造函数
BigNum &operator=(const BigNum &); //重载赋值运算符,大数之间进行赋值运算
friend istream& operator>>(istream&,BigNum&); //重载输入运算符
friend ostream& operator<<(ostream&,BigNum&); //重载输出运算符
BigNum operator+(const BigNum &)const; //重载加法运算符,两个大数之间的相加运算
BigNum operator-(const BigNum &)const; //重载减法运算符,两个大数之间的相减运算
BigNum operator*(const BigNum &)const; //重载乘法运算符,两个大数之间的相乘运算
BigNum operator/(const int &)const; //重载除法运算符,大数对一个整数进行相除运算
BigNum operator^(const int &)const; //大数的n次方运算
int operator%(const int &)const; //大数对一个int类型的变量进行取模运算
bool operator>(const BigNum &T)const; //大数和另一个大数的大小比较
bool operator>(const int &t)const; //大数和一个int类型的变量的大小比较
void print(); //输出大数
};
BigNum::BigNum(const int b) { //将一个int类型的变量转化为大数
int c,d=b;
len=;
memset(a,,sizeof(a));
while(d>MAXN) {
c=d-(d/(MAXN+))*(MAXN+);
d=d/(MAXN+);
a[len++]=c;
}
a[len++]=d;
}
BigNum::BigNum(const char *s) { //将一个字符串类型的变量转化为大数
int t,k,index,L,i;
memset(a,,sizeof(a));
L=strlen(s);
len=L/DLEN;
if(L%DLEN)len++;
index=;
for(i=L-; i>=; i-=DLEN) {
t=;
k=i-DLEN+;
if(k<)k=;
for(int j=k; j<=i; j++)
t=t*+s[j]-'';
a[index++]=t;
}
}
BigNum::BigNum(const BigNum &T):len(T.len) { //拷贝构造函数
int i;
memset(a,,sizeof(a));
for(i=; i<len; i++)
a[i]=T.a[i];
}
BigNum & BigNum::operator=(const BigNum &n) { //重载赋值运算符,大数之间赋值运算
int i;
len=n.len;
memset(a,,sizeof(a));
for(i=; i<len; i++)
a[i]=n.a[i];
return *this;
}
istream& operator>>(istream &in,BigNum &b) {
char ch[MAXSIZE*];
int i=-;
in>>ch;
int L=strlen(ch);
int count=,sum=;
for(i=L-; i>=;) {
sum=;
int t=;
for(int j=; j<&&i>=; j++,i--,t*=) {
sum+=(ch[i]-'')*t;
}
b.a[count]=sum;
count++;
}
b.len=count++;
return in;
}
ostream& operator<<(ostream& out,BigNum& b) { //重载输出运算符
int i;
cout<<b.a[b.len-];
for(i=b.len-; i>=; i--) {
printf("%04d",b.a[i]);
}
return out;
}
BigNum BigNum::operator+(const BigNum &T)const { //两个大数之间的相加运算
BigNum t(*this);
int i,big;
big=T.len>len?T.len:len;
for(i=; i<big; i++) {
t.a[i]+=T.a[i];
if(t.a[i]>MAXN) {
t.a[i+]++;
t.a[i]-=MAXN+;
}
}
if(t.a[big]!=)
t.len=big+;
else t.len=big;
return t;
}
BigNum BigNum::operator-(const BigNum &T)const { //两个大数之间的相减运算
int i,j,big;
bool flag;
BigNum t1,t2;
if(*this>T) {
t1=*this;
t2=T;
flag=;
} else {
t1=T;
t2=*this;
flag=;
}
big=t1.len;
for(i=; i<big; i++) {
if(t1.a[i]<t2.a[i]) {
j=i+;
while(t1.a[j]==)
j++;
t1.a[j--]--;
while(j>i)
t1.a[j--]+=MAXN;
t1.a[i]+=MAXN+-t2.a[i];
} else t1.a[i]-=t2.a[i];
}
t1.len=big;
while(t1.a[len-]== && t1.len>) {
t1.len--;
big--;
}
if(flag)
t1.a[big-]=-t1.a[big-];
return t1;
}
BigNum BigNum::operator*(const BigNum &T)const { //两个大数之间的相乘
BigNum ret;
int i,j,up;
int temp,temp1;
for(i=; i<len; i++) {
up=;
for(j=; j<T.len; j++) {
temp=a[i]*T.a[j]+ret.a[i+j]+up;
if(temp>MAXN) {
temp1=temp-temp/(MAXN+)*(MAXN+);
up=temp/(MAXN+);
ret.a[i+j]=temp1;
} else {
up=;
ret.a[i+j]=temp;
}
}
if(up!=)
ret.a[i+j]=up;
}
ret.len=i+j;
while(ret.a[ret.len-]== && ret.len>)ret.len--;
return ret;
}
BigNum BigNum::operator/(const int &b)const { //大数对一个整数进行相除运算
BigNum ret;
int i,down=;
for(i=len-; i>=; i--) {
ret.a[i]=(a[i]+down*(MAXN+))/b;
down=a[i]+down*(MAXN+)-ret.a[i]*b;
}
ret.len=len;
while(ret.a[ret.len-]== && ret.len>)
ret.len--;
return ret;
}
int BigNum::operator%(const int &b)const { //大数对一个 int类型的变量进行取模
int i,d=;
for(i=len-; i>=; i--)
d=((d*(MAXN+))%b+a[i])%b;
return d;
}
BigNum BigNum::operator^(const int &n)const { //大数的n次方运算
BigNum t,ret();
int i;
if(n<)exit(-);
if(n==)return ;
if(n==)return *this;
int m=n;
while(m>) {
t=*this;
for(i=; (i<<)<=m; i<<=)
t=t*t;
m-=i;
ret=ret*t;
if(m==)ret=ret*(*this);
}
return ret;
}
bool BigNum::operator>(const BigNum &T)const { //大数和另一个大数的大小比较
int ln;
if(len>T.len)return true;
else if(len==T.len) {
ln=len-;
while(a[ln]==T.a[ln]&&ln>=)
ln--;
if(ln>= && a[ln]>T.a[ln])
return true;
else
return false;
} else
return false;
} bool BigNum::operator>(const int &t)const { //大数和一个int类型的变量的大小比较
BigNum b(t);
return *this>b;
}
void BigNum::print() { //输出大数
int i;
printf("%d",a[len-]);
for(i=len-; i>=; i--)
printf("%04d",a[i]);
printf("\n");
} typedef struct {
int pos;
int val;
} Num; Num A[N];
BigNum dp[N][N], c[N]; void Init(int n)
{
for(int i = ; i <= n; i++) {
dp[i][] = ;
for(int j = ; j <= i; j++) {
dp[i][j] = ;
}
}
} int Lowbit(int x)
{
return x & (-x);
} void Add(int x, BigNum val, int n)
{
while(x <= n) {
c[x] = c[x] + val;
x += Lowbit(x);
}
} BigNum Sum(int x)
{
BigNum sum = ;
while(x > ) {
sum = sum + c[x];
x -= Lowbit(x);
}
return sum;
} bool cmp(Num a, Num b)
{
if(a.val == b.val) return a.pos > b.pos;
else return a.val < b.val;
} int main()
{
int n, k; while(scanf("%d %d", &n, &k) != EOF) {
Init(n);
for(int i = ; i <= n; i++) {
scanf("%d", &A[i].val);
A[i].pos = i;
}
sort(A+, A+n+, cmp);
for(int i = ; i <= k; i++) {
for(int j = ; j <= n; j++) {
c[j] = ;
}
for(int j = ; j <= n; j++) {
Add(A[j].pos, dp[j][i-], n);
dp[j][i] = dp[j][i] + Sum(A[j].pos - );
}
}
BigNum ans = ;
for(int i = k; i <= n; i++) {
ans = ans + dp[i][k];
}
ans.print();
} return ;
}

HDU 5568 - BestCoder Round #63 - sequence2的更多相关文章

  1. hdu 5667 BestCoder Round #80 矩阵快速幂

    Sequence  Accepts: 59  Submissions: 650  Time Limit: 2000/1000 MS (Java/Others)  Memory Limit: 65536 ...

  2. hdu 5643 BestCoder Round #75

    King's Game  Accepts: 249  Submissions: 671  Time Limit: 2000/1000 MS (Java/Others)  Memory Limit: 6 ...

  3. hdu 5641 BestCoder Round #75

    King's Phone  Accepts: 310  Submissions: 2980  Time Limit: 2000/1000 MS (Java/Others)  Memory Limit: ...

  4. HDU5568/BestCoder Round #63 (div.2) B.sequence2 dp+高精度

    sequence2 Problem Description Given an integer array bi with a length of n, please tell me how many ...

  5. HDU 5682/BestCoder Round #83 1003 zxa and leaf 二分+树

    zxa and leaf Problem Description zxa have an unrooted tree with n nodes, including (n−1) undirected ...

  6. HDU 5506 - BestCoder Round #60 - GT and set

    题目链接 : http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=641&pid=1003 题意 : 给N集 ...

  7. HDU 5505 - BestCoder Round #60 - GT and numbers

    题目链接 : http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=641&pid=1002 思路 : N有若 ...

  8. HDU 5496 - BestCoder Round #58 - Beauty of Sequence

      题目链接 : http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=637&pid=1002 思路 : 考 ...

  9. hdu 5637 BestCoder Round #74 (div.2)

    Transform  Accepts: 7  Submissions: 49  Time Limit: 4000/2000 MS (Java/Others)  Memory Limit: 131072 ...

随机推荐

  1. Linux磁盘管理:LVM逻辑卷的拉伸及缩减

    ①查看当前VG的信息,保证VG中有足够的空闲空间 通过 vgdisplay 或者 vgs 命令 [root@rusky ~]# vgs rusky-vg VG #PV #LV #SN Attr VSi ...

  2. Android签名详解(debug和release)

    Android签名详解(debug和release)   1. 为什么要签名 1) 发送者的身份认证 由于开发商可能通过使用相同的Package Name来混淆替换已经安装的程序,以此保证签名不同的包 ...

  3. python栈的实现(入栈,出栈)

    #coding=utf-8 class Stack(): def __init__(st,size):#栈的初始化 st.stack=[]; st.size=size; st.top=-1 def p ...

  4. ASP.NET5中间件

    小的应用组件可以包含到Http请求管道当中,ASP.NET5 集成了中间件,被包在了应用程序的Configure方法当中. 1. 什么是中间件 中间件是一组被装到应用程序管道的请求和响应中的组件.每一 ...

  5. js字符串比较

    1,大写字母小于小写字母 a='ang',b='Zh' 那么a>b 2,可以使用字符串的toUpperCase()/toLowerCase()方法不区分字母的大小写. a.toUpperCase ...

  6. UIViewController的View显示在导航栏下面如何解决?

    ios7之前的版本中UIViewController中的view在显示后会自动调整为去掉导航栏的高度的,控件会自动在导航栏以下摆放. 在iOS7中UIViewController的wantsFullS ...

  7. 重新开始学习javase_集合_Set

    一,Set之HashSet(转:http://blog.csdn.net/zheng0518/article/details/42197337) 1.    HashSet概述: HashSet实现S ...

  8. inputtype

    <EditText android:layout_width="fill_parent" android:layout_height="wrap_content&q ...

  9. 初涉JavaScript模式 (5) : 原型模式 【一】

    什么是原型模式? 原型模式(prototype)是指用原型实例指向创建对象的种类,并且通过拷贝这些原型创建新的对象.--引自JavaScript设计模式 我们创建的每一个函数都有一个prototype ...

  10. angularJS中如何写服务

    服务的用途 服务提供了一种能在应用的整个生命周期内保持数据的方法,它能够在控制器之间进行通信,并且能保证数据的一致性 服务提供了把特定功能相关联的方法集中在一起的接口 如何创建服务 angularJS ...