HDU 5568 - BestCoder Round #63 - sequence2
题目链接 : 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的更多相关文章
- hdu 5667 BestCoder Round #80 矩阵快速幂
Sequence Accepts: 59 Submissions: 650 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536 ...
- hdu 5643 BestCoder Round #75
King's Game Accepts: 249 Submissions: 671 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 6 ...
- hdu 5641 BestCoder Round #75
King's Phone Accepts: 310 Submissions: 2980 Time Limit: 2000/1000 MS (Java/Others) Memory Limit: ...
- 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 ...
- 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 ...
- HDU 5506 - BestCoder Round #60 - GT and set
题目链接 : http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=641&pid=1003 题意 : 给N集 ...
- HDU 5505 - BestCoder Round #60 - GT and numbers
题目链接 : http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=641&pid=1002 思路 : N有若 ...
- HDU 5496 - BestCoder Round #58 - Beauty of Sequence
题目链接 : http://bestcoder.hdu.edu.cn/contests/contest_chineseproblem.php?cid=637&pid=1002 思路 : 考 ...
- hdu 5637 BestCoder Round #74 (div.2)
Transform Accepts: 7 Submissions: 49 Time Limit: 4000/2000 MS (Java/Others) Memory Limit: 131072 ...
随机推荐
- Protobuf的自动反射消息类型的方法
1. 每个消息头部中带上type name,作为消息的类型标识 2. 通过type name可以找到描述符Descriptor*, FindMessageTypeByName 3. 通过描述符Desc ...
- 关于 yii 验证码显示, 但点击不能刷新的处理
先说说 render 与 renderPartial, 各位看官, 先别走, 我没跑题, 这个问题如果需要解决, 关键就在 render 与 renderPartial 的区别. renderPart ...
- verilog之task用法实例
该用法的代码源自夏宇闻老师的教材. 源代码: module traffic_lights; reg clock, red, amber, green; , off = , red_tics = , a ...
- jQuery创建ajax关键词数据搜索
在web开发过程当中,我们经常需要在前台页面输入关键词进行数据的搜索,我们通常使用的搜索方式是将搜索结果用另一个页面显示,这样的方式对于搭建高性能网站来说不是最合适的,今天给大家分享一下如何使用 jQ ...
- 【转】Objective-C中一种消息处理方法performSelector: withObject:
原文 : http://www.cnblogs.com/buro79xxd/archive/2012/04/10/2440074.html Objective-C中调用函数的方法是“消息传递”,这 ...
- NSString截取字符串
NSString 是经常会用到的,很多时候需要对字符串进行一些处理,本文简单介绍字符串截取操作: 比如: 1.定义一个字符串a, 截取a的某一个部分(子串) NSString *a = @" ...
- iOS开发中EXC_BAD_ACCESS的另类原因
今天偶然学习iOS开发的时候碰到一个EXC_BAD_ACCESS的异常,经查资料得到的解释是由于访问了已经被回收了堆内存对象导致的,参考: http://code.tutsplus.com/tutor ...
- Object Storage(Swift)安装过程——Havana
自从看了Havana安装文档有关Swift的安装一节,发现H版的安装过程与以前还是有些差别的.不过大致过程还是那些.下面简单介绍下我们安装的过程吧,具体请参考官方文档http://docs.opens ...
- JS响应事件整理
javascript事件列表解说 事件 浏览器支持 解说 一般事件 onclick IE3.N2 鼠标点击时触发此事件 ondblclick IE4.N4 鼠标双击时触发此事件 onmousedown ...
- linux makefle学习
学习材料取之这个网址:http://blog.chinaunix.net/uid-27717694-id-3696246.html 学习环境:ubuntu10.04-64bit-desktop版,gc ...