题目链接 : 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. Sublime Text3使用详解

    Sublime Text简介 Sublime Text - 性感的代码编辑器.程序员之必备神器 Sublime Text 是一个代码编辑器,也是HTML和散文先进的文本编辑器.Sublime Text ...

  2. Warning once only: Detected a case where constraints ambiguously suggest a height of zero for a tableview cell's content view...

    Warning once only: Detected a case where constraints ambiguously suggest a height of zero for a tabl ...

  3. directshow filter 调试步骤

    1,编写filter 2,在debug模式下build 3,注册filter:控制台cd到工程的debug目录下,即欲注册的filter(.ax文件)目录,xx:>regsvr32 contra ...

  4. apple

    you are the apple of my eye

  5. 安卓应用开发用户体验之禁止EditText自动获取焦点

    一.问题描述: 在安卓应用开发时,经常会在同一个页面有许多不同的控件,在用户操作时,如何正确的在这些控件之间来回切换是良好用户体验的重要问题.可能会碰到如下问题:在点击页面内某控件时(假设控件为Spi ...

  6. sae crop 文档

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

  7. (转)Android Studio系列教程一下载与安装 背景Android Studio VS Eclipse准备下载创建HelloWorld项目

    背景 相信大家对Android Studio已经不陌生了,Android Studio是Google于2013 I/O大会针对Android开发推出的新的开发工具,目前很多开源项目都已经在采用,Goo ...

  8. jquery 文本框聚焦文字删除

    做作业需要,自己写了一个,写的很烂. $(function() { $("#search_input").addClass("before_focus");/* ...

  9. HTML语义化标签(二)

    为了保证网页去样式后的可读性,并且又符合web标准,应该注意一下几点: 1  尽可能少的使用无语义的标签div和span: 2  在语义不明显时,既可以使用div或者p时,尽量用p, 因为p在默认情况 ...

  10. oracle触发器应用

    首先给大家推荐两篇我看后的博文,我已经内容转载过来: 1.对触发器的讲解 本篇主要内容如下: 8.1 触发器类型 8.1.1 DML触发器 8.1.2 替代触发器 8.1.3 系统触发器 8.2 创建 ...