Time: 2014.4.21~2014.4.27
poj3176
题意:数塔
思路:dp[i][j]=max(dp[i-1][j-1],dp[i-1][j])+a[i][j];
Code: poj3176.cpp
poj2229
题意:仅用1,2,4,8...组成n的方案数对10^9取余
思路:n为奇数 dp[n]=dp[n-1] (写成 dp[n]=dp[n-1]+dp[n-2]+dp[n-4]+... 的话想想,是不是会算重)
同理,n为偶数 dp[n]=dp[n-1]+dp[n/2] (在n-1的方案上加一个1,或者直接取n/2的方案的全部两倍,后者方案中不存在1)
Code: poj2229.cpp
poj2385
题意:两个树分别在不同时间内(n<=1000)掉苹果,中途能从一棵树到另一颗树下等(不超过w次,w<=30),求最大苹果数。
思路:dp[now][i][j] 表示 当前处在树now下,i时刻,移动次数为j的情况下的苹果数。
dp[1][i][j]=max(dp[1][i-1][j]+(v[i]==1),dp[2][i-1][j-1]+(v[i]==2));
dp[2][i][j]=max(dp[2][i-1][j]+(v[i]==2),dp[1][i-1][j-1]+(v[i]==1));
Code: poj2385.cpp
uva10025
题意:式子?1?2?3?...?n=k (abs(k)<=10^9) ?用‘+’或‘-’代替
思路:枚举n,当前n项和大于等于k,且它们的差值是个偶数的时候,即为最小n
因为前n项和内任意数字均可用1~n中的若干项相加得到,所以差值的一半可以由某些数字表示,并减去
Code: uva10025.cpp
hdu2066
题意:裸的dijkstra
思路:注意双向边
Code: hdu2066.cpp
poj3616
题意:给出m(<=1000)个产奶的开始结束时间以及产量,每次产奶后休息r分钟,求n(1<=n<=100w)的时间最多产多少
思路:对输入的时间段,按照结束时间排序,用dp[i]表示前i时间能够获取的最大值if(i==p[now].ed+r) dp[i]=max(dp[i],dp[p[now].st]+p[now].ef);
else dp[i]=ans; // ans表示当前获取的最大值
这题要注意的是,时间段存在相同的结束时间,不同的产量等,都会有影响
Code: poj3616.cpp
poj3280
题意:输入删除或插入某个字母的代价,求最小代价把某个字符串(length<=1000)变成回文串
思路:删除和插入操作其实是一样的,直接取最小值,用dp[i][j]表示将区间[i,j]变成回文串的最小代价
dp[i][j]=min(dp[i][j],dp[i+1][j]+val[s[i]-'a'],dp[i][j-1]+val[s[j]-'a']);
if(s[i]==s[j]) dp[i][j]=min(dp[i][j],dp[i+1][j-1]);
Code: poj3280.cpp
poj1742
题意:求1~m(<=10w)中数字用c[i]枚价值为a[i]的硬币(n<=100种)能组成多少
思路:一般的做法是母函数或者多重背包,但是都会TLE (男人八题)
白书上的做法是,枚举每种硬币,用dp[i]表示当前枚举硬币下,组成价值i后还剩下硬币dp[i]枚数可选
if(dp[j]>=0) dp[j]=c[i];
else if(j<a[i] || dp[j-a[i]]<0) dp[j]=-1; // 不可达
else dp[j]=dp[j-a[i]]-1;
Code:poj1742.cpp
poj3181
题意:求用1~k(<=100)的数字表示n(<=1000)的方案数
思路:枚举i个数字,dp[j]+=dp[j-i]; java大数
Code: poj3181.java
poj3046
题意:求A只蚂蚁分成[S,B]个集合的不重复组合的方案数取模,蚂蚁根据种类分为啥啥
思路:1.生成函数+暴力(easy)
2.dp+优化递推关系式
dp[i][j]表示前i个数已经取了j个的方案数,边界dp[i][0]=1
dp[i+1][j]=sigma(0<=k<=min(j,a[i]))dp[i][j-k];
=sigma(0<=k<=min(j-1,a[i]))dp[i][j-1-k]+dp[i][j]-dp[i][j-1-a[i]];
=dp[i+1][j-1]+dp[i][j]-dp[i][j-1-a[i]];
复杂度O(T*B)
Code: poj3046.cpp
poj1065
题意:求最少能分成多少个连续不下降的二维子序列
思路:跟导弹那题一样,求一个反向的最长上升子序列
for(int i=0;i<n;i++) *lower_bound(dp,dp+n,vt[i])=vt[i]; return lower_bound(dp,dp+n,INF)-dp;
Code: poj1065.cpp
poj1631
题意:裸的LIS
思路:LIS
Code: poj1631.cpp
poj3666
题意:将给定序列变成不递增或不递减的最小花费
思路:dp[i][j]表示枚举到第i位,且第i位的值将改为p[j](p数组为离散化排序的结果)的最小花费
dp[i][j]=min(dp[i-1][k](1<=k<=j))+abs(a[i]-p[j]); (好题)
Code: poj3666.cpp
zoj3203
题意:求一个高h的人,在一盏高度为H的灯下,灯距离墙D,地上影子和墙上影子的和的最大值
思路:设人到灯的距离为x,墙上影子存在的条件为 x>D*(H-h)/H,设墙上影子为y
那么 D/(H-y)=(D-x)/(h-y) so y=H-(H-h)*D/x,ans=D-x+y
ans=H+D-(x+(H-h)*D/x) 后面部分算上负号是一个先递增后递减的函数,凸性函数用三分法求极值
Code: zoj3203.cpp
poj2392
题意:K(<=400)种block,每种c(<=10)个,且处在海拔不会超过a(<=4w),求block堆起来的最大海拔
思路:总的block不超过K*c个,也就是4000,按照海拔排序后,01背包
for(int i=0;i<now;i++) for(int j=p[i].a;j>=p[i].h;j--) dp[j]=max(dp[j-p[i].h],dp[j]);
Code: poj2392.cpp
poj2184
题意:n(<=100)头牛,每头牛都有两个属性,求两个属性和大于等于0的情况下,属性和的最大值
思路:将原点移动,使得负值全变成正值,然后01背包
Code:poj2184.cpp
hdu4355
题意:求所有点到某个点距离的三次方乘上权重后和的最小值
思路:sigma(fabs(x[i]-x)^3*w[i]) 三分 单调性么,无从证明
Code: hdu4355.cpp
hdu3714
题意:f(x)=max(a[i]*x*x+b[i]*x+c[i]) 0<=x<=1000
思路:三分
Code: hdu3714.cpp
poj3735
题意:n(<=100)只猫,k(<=100)次操作,g表示加x,e表示清空,s表示交换,然后这套操作进行m(<=10^9)次
思路:构造稀疏矩阵
矩阵优化:
Matrix multi(Matrix A,Matrix B){
Matrix ans; memset(ans.m,0,sizeof(ans.m));
for(int i=1;i<=n;i++)
for(int k=1;k<=n;k++){
if(A.m[i][k]==0) continue;
for(int j=1;j<=n;j++)
ans.m[i][j]+=A.m[i][k]*B.m[k][j];
}
return ans;
}
Code: poj3735.cpp
poj2686
题意:n(<=8)张票,每张票有t[i]的马力,有m(<=30)个城市,p条边,表示x到y的距离是d,求城市a到b的最小时间
思路:用dp[s][v]表示n张票可用的票的集合为s,当前处在城市i的最小时间
dp[s&(~(1<<i))][v]=min(dp[s&(~(1<<i))],dp[s][u]+d[u][v]/t[i]);
Code: poj2686.cpp
poj2441
题意:n(<=20)头牛,m(<=20)个仓库,已知每头牛可以去哪些仓库,求方案数
思路:dp[i][j]表示安置前i头牛后,当前状态为j的方案数,滚动数组优化一下
for(int j=0;j<v[i].size();j++){
if(state&(1<<v[i][j]))
dp[i&1][state]+=dp[1-(i&1)][state&(~(1<<v[i][j]))];
}
Code: poj2441.cpp