题目链接 : 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. POJ 2559 Largest Rectangle in a Histogram (单调栈或者dp)

    Largest Rectangle in a Histogram Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 15831 ...

  2. Python之路,Day15 - Django适当进阶篇

    Python之路,Day15 - Django适当进阶篇   本节内容 学员管理系统练习 Django ORM操作进阶 用户认证 Django练习小项目:学员管理系统设计开发 带着项目需求学习是最有趣 ...

  3. My.Ioc 代码示例——注册项的注销和更新

    当您需要从 Ioc 容器中注销/删除一个注册项的时候,您会怎么做呢? 有人曾经在 stackoverflow 上提问“如何从 Unity 中注销一个注册项”.对于这个问题,有人的回答是“有趣.你为什么 ...

  4. Html5 Canvas Text

    html5 canvas中支持对text文本进行渲染;直接的理解就是把text绘制在画布上,并像图形一样处理它(可以加shadow.gradient.pattern.color fill等等):既然它 ...

  5. oracle系统包——dbms job用法(oracle定时任务)

    用于安排和管理作业队列,通过使用作业,可以使ORACLE数据库定期执行特定的任务. 一.dbms_job涉及到的知识点1.创建job:variable jobno number;dbms_job.su ...

  6. [转帖]AVS音视频编解码技术了解

    AVS高清立体视频编码器 电视技术在经历了从黑白到彩色.从模拟到数字的技术变革之后正在酝酿另一场技术革命,从单纯观看二维场景的平面电视跨越到展现三维场景的立体电视3DTV.3DTV系统的核心问题之一是 ...

  7. 解决 iOS View Controller Push/Pop 时的黑影

    那么如何解决这个问题呢? 实际上很简单,如果这个 ViewController 是在 TabBarViewController 的 NavigationController 上 Push/Pop 的, ...

  8. javascript之typeof、constructor、instanceof

    ref: http://jingyan.baidu.com/article/29697b912f9939ab20de3c8c.html

  9. sae crop 文档

    原文是google缓存:http://webcache.googleusercontent.com/search?q=cache:MD_FP-G6RI8J:sae.sina.com.cn/%3Fm%3 ...

  10. 深入Java虚拟机读书笔记第二章平台无关性

    Java的体系结构对平台无关的支持 Java平台 Java的体系结构通过几种途径支持Java程序的平台无关性,其中主要是通过Java平台自己.Java平台扮演一个运行时Java程序与其下的硬件和操作系 ...