emmm,这个系列似乎没那么水了><
DP系列,虽然个人觉得第一题没那么典型,不过确实也用到了自底向上的递推。
hdoj 2062
思路:递推求解每个分组中数的个数
注意:1、long long 和 %lld(Runtime Error(ACCESS_VIOLATION) or WA...)
2、字典序
3、m要减去空集的情况
//hdoj 2062
#include
//in lexicography order按字典序
int main(){
int n;
long long m;
long long cnt[21];
int val[21];
cnt[1]=1;
for(int i=2;i<21;++i){//递推!!!
cnt[i]=(i-1)*cnt[i-1]+1;//n=i时,每个分组中的数的个数
}
while(scanf("%d %lld",&n,&m)!=EOF){//%lld!!
for(int i=0;i<21;++i){
val[i]=i;//字典中的元素
}
while(n&&m){
int a=(m-1)/cnt[n]+1;//第a组 或
//int a=m/cnt[n]+(m%cnt[n]==0?0:1);
printf("%d",val[a]);
//后面不能再出现这个元素,字典中这个元素后面的元素前移
for(int i=a;i
hdoj 1087
DP 空间换时间
//hdoj 1087 求序列中最大的递增子序列累计和
#include
#include////max,max_element
#include
//#include
//#include
using namespace std;
int main(){
int n;//31MS 1888K
while(scanf("%d",&n),n){
vector v(n);
for(int i=0;i maxv(n,0);
vector sum(n,0);
vector tail(n,0);
sum[0]+=v[0];
maxv[0]=max(sum[0],maxv[0]);
tail[0]=v[0];
for(int i=1;i=0;--j){//遍历递减序列(46MS 1916K)//long long n;vector v(n);
if(v[i]-v[j]>0&&(v[j]>tail[i])){
tail[i]=v[j];
sum[i]=v[i]+maxv[j];
maxv[i]=max(maxv[i],sum[i]);
}
}
if(maxv[i]==0) maxv[i]=v[i];
}
printf("%lld\n",*max_element(maxv.begin(),maxv.end()));//*max_element!!!
}
return 0;
}
hdoj 1203
DP 01背包+乘积最小
用一维数组改善空间,循环时仍用两重循环,注意j要逆序!(参考这篇博客)
//hdoj 1203 01背包+乘积最小
#include
#include
#include
#include ///设置格式
#include //格式输出更方便
using namespace std;
int main(){
int n,m;
//cout<>n>>m,n||m){
while(scanf("%d %d",&n,&m),n||m){//memory较小 time差不多
vector cost(m+1);//全部+1!!!
vector p_s(m+1);//double
vector p_f(m+1,1);
vector minp_f(n+1,1);
for(int i=1;i<=m;++i){
//cin>>cost[i]>>p_s[i];
scanf("%d %lf",&cost[i],&p_s[i]);
p_f[i]-=p_s[i];
}
//两重循环!不能调换内外循环次序 否则将利用到i=m的minp_f[j]值
for(int i=1;i<=m;++i){
for(int j=n;;--j){//j 逆序!i和i-1存储在同一个minp_f[j]中 i会将i-1覆盖
if(j
hdoj 1003
DP 最大的子序列累计和,外加子序列头尾所在的位置
sum记录当前的累计和,maxv从全局考虑
len.......................序列长,si,ei......................
搭配着修改
//hdoj 1003 最大的子序列累计和
#include
#include
using namespace std;
int main(){
int t;
scanf("%d",&t);
for(int i=0;i0) printf("\n");/////otherwise PE
int n;
scanf("%d",&n);
vector v(n);
for(int j=0;j=0){
sum+=v[j];//记录包含v[j]的子序列的累计和
++len;///未必是最大累积和子序列中的部分(未必参与si的计算)
///但是当前序列还有后续 最后也有可能在最大累积和子序列中
///所以要另设len进行记录
}
else{
sum=v[j];//前面的部分为负 对包含v[j]的序列累计和只有负贡献 因此重新累加
len=1;////
}
if(sum>maxv){///只要sum改变 就有可能超过maxv 上面if else中都更新了sum
maxv=sum;
ei=j;
si=ei-len+1;///maxv更新时同步更新ei和si 而不是在最后才更新
}
}
printf("Case %d:\n",i+1);
printf("%lld %d %d\n",maxv,si+1,ei+1);//
}
return 0;
}