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 ...
随机推荐
- Android(java)学习笔记244:多媒体之SurfaceView
1. SurfaceView: 完成单位时间内界面的快速切换(游戏界面流畅感). 我们之前知道一般的View,只能在主线程里面显示,主线程中更新UI.但是SurfaceView可以在子线程中里 ...
- 转:SVN使用教程总结
转自:http://www.cnblogs.com/tugenhua0707/p/3969558.html SVN简介: 为什么要使用SVN? 程序员在编写程序的过程中,每个程序员都会生成很多不同的版 ...
- angular中ueditor插件的使用
#在angularjs中使用ueditor编辑器需要注意事项: 在ui-view中使用放置ueditor的div,页面加载时编辑器在页面中是不显示的,需要通过指令手动replay 例: /** * u ...
- querystring,parse和stringify相互转换
var querystring = require('querystring');var str = 'name==zfpx@age==8';//手工指定字段分隔符和 keyvalue分隔符var q ...
- 一个类实现多个接口的demo
//A接口 interface A{ public int getA(); } //B接口 interface B{ public int getB(); } //实现了某个接口必须实现其全部的方法 ...
- UITabBarController自定义一
UITabBarController自定义一 首先在Appdelegate.m文件中将UITabBarController的子类设置为rootViewController,并设置其viewContro ...
- ExtJs API 下载以及部署
ExtJs API 下载方法 1.进入sencha官网:https://www.sencha.com/ 2.点击“Docs”进入文档帮助页面:http://docs.sencha.com/ 3.点击左 ...
- 实现textarea限制输入字数
实现textarea限制输入字数(包含中文只能输入10个,全ASCII码能够输入20个) textarea称文本域,又称文本区,即有滚动条的多行文本输入控件,在网页的提交表单中经常用到.与单行文本框t ...
- JS动态加载 js css
1.动态加载js function loadScript( url ){ var script = document.createElement( "script" ); scri ...
- python运维开发之第十天
一.多进程 1.进程模块 multiprocessing 简单的创建一个进程 #!/usr/bin/env python # -*- coding: utf- -*- # @Author : Will ...