前言:

  话说DP这种纯考思维的题目,总是让我很伤脑筋,一些特别简单的DP我都常常做不出来,所以革命从现在(2018-05-01)开始,努力多刷点DP的练习~。

1.顺序对齐(align)

时间:2018-05-01

Description
  考虑两个字符串右对齐的最佳解法。例如,有一个右对齐方案中字符串是AADDEFGGHC 和 ADCDEGH 。

  AAD_DEFGGHC
  ADCDE__GH_
  每一个数值匹配的位置值 +2分,一段连续的空格值 -1 分。所以总分是匹配点的 2 倍减去连续空格的段数,在上述给定的例子中, 6 个位置(A,D,D,E, G,H )匹配,三段空格,所以得分2*6+(-1)*3=9 ,注意,我们并不处罚左边的不匹配位置。若匹配的位置是两个不同的字符,则既不得分也不失分。请你写个程序找出最佳右对齐方案。
Input
  输入文件包含两行,每行一个字符串,最长50 个字符。字符全部是大字字母。
Output
  一行,为最佳对齐的得分。
Sample Input
  AADDEFGGHC
  ADCDEGH
Sample Output
  9

Solution:

  由题意,归纳出以下信息:串$s1$和串$s2$的每一次匹配,只有$4$种情况:两个字符相同得$2$分、两个字符不同$s1$用空格匹配$-1$分、两个字符不同$s2$用空格匹配$-1$分、两个字符不同也不加空格得$0$分。

  于是我们不难定义状态$f[i][j]$表示匹配到$s1$串的第$i$个位置和$s2$串的第$j$个位置时能得到的最大分数,则目标状态$f[l1][l2]$($l1=|s1|,l2=|s2|$)。

  那么从上面的分析中不难得到状态转移方程:

$f[i][j]=$$\left\{\begin{matrix}
 max(f[i][j],f[i-1][j-1]+2)\quad if(s1[i]==s2[j]) \\
 max(f[i][j],f[k][j]-1)\quad k\in[1,i) \\
 max(f[i][j],f[i][k]-1)\quad k\in[1,j) \\
 max(f[i][j],f[i-1][j-1])\quad if(s1[i]!=s2[j]) \\
\end{matrix}\right.$

  时间复杂度$O(n^3),n\leq 50$,稳过。

代码:

 #include<bits/stdc++.h>
#define il inline
#define Max(a,b) (a)>(b)?(a):(b)
#define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
using namespace std;
const int N=;
char s1[N],s2[N];
int f[N][N],l1,l2;
int main(){
scanf("%s%s",s1+,s2+);
l1=strlen(s1+),l2=strlen(s2+);
For(i,,l1) For(j,,l2) {
if(s1[i]==s2[j])f[i][j]=Max(f[i][j],f[i-][j-]+);
For(k,,i-)f[i][j]=Max(f[i][j],f[k][j]-);
For(k,,j-)f[i][j]=Max(f[i][j],f[i][k]-);
f[i][j]=Max(f[i][j],f[i-][j-]);
}
cout<<f[l1][l2];
return ;
}

 

2、任务安排(batch)

时间:2018-05-01

Description

N个任务排成一个序列在一台机器上等待完成(顺序不得改变),这N个任务被分成若干批,每批包含相邻的若干任务。从时刻0开始,这些任务被分批加工,第i个任务单独完成所需的时间是Ti。在每批任务开始前,机器需要启动时间S,而完成这批任务所需的时间是各个任务需要时间的总和(同一批任务将在同一时刻完成)。每个任务的费用是它的完成时刻乘以一个费用系数Fi。请确定一个分组方案,使得总费用最小。

例如:S=1;T={1,3,4,2,1};F={3,2,3,3,4}。如果分组方案是{1,2}、{3}、{4,5},则完成时间分别为{5,5,10,14,14},费用C={15,10,30,42,56},总费用就是153。

Input

第一行是N(1<=N<=5000)。

第二行是S(0<=S<=50)。

下面N行每行有一对数,分别为Ti和Fi,均为不大于100的正整数,表示第i个任务单独完成所需的时间是Ti及其费用系数Fi。

Output

一个数,最小的总费用。

Sample Input

 5
 1
 1 3
 3 2
 4 3
 2 3
 1 4

Sample Output

153

Solution:

  分析本题,可以发现,每多一批任务,等价于使后面的每个机器费用增加对应的费用系数乘上$s$,而每一批任务的总时间应该等于这批任务本来的结束时间(即当前为位置时间$t$的前缀和)加上前面的几批任务增加的时间$s$,该批的总花费就是当前总时间乘这一段的费用系数之和。

  于是定义状态$f[i]$表示到了第$i$个任务时的最小费用,初始状态$f[0]=0$(由于要最小费用,其它的$f[i]$初始化为$inf$),用$t[i]$表示到了第$i$个任务的时间前缀,$c[i]$表示到了第$i$个任务的费用系数前缀。

  不难得到状态转移方程:$f[i]=min(f[i],f[j]+t[i]*(c[i]-c[j])+s*(c[n]-c[j]))$,表示当前以第$i$个任务为新的一批的末尾,枚举上一批的结束位置$j$(当前这批的开始位置为$j+1$),则该批任务$j+1$到$i$的花费为上一批的任务花费$f[j]$加上新的这一批任务本来的花费$t[i]*(c[i]-c[j])$和增加的$s$的花费$s*(c[n]-c[j])$(注意增加的花费的费用系数和是$c[n]-c[j]$,因为多一批任务后面的每个任务所需时间都会加$s$)。

  最后输出目标状态$f[n]$就$ok$了。

代码:

 #include<bits/stdc++.h>
#define il inline
#define Min(a,b) (a)>(b)?(b):(a)
#define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
using namespace std;
const int N=;
int n,s,t[N],c[N],f[N];
int main(){
ios::sync_with_stdio();
cin>>n>>s;
memset(f,0x3f,sizeof(f));f[]=;
For(i,,n)cin>>t[i]>>c[i],t[i]+=t[i-],c[i]+=c[i-];
For(i,,n) For(j,,i-) f[i]=Min(f[i],f[j]+t[i]*(c[i]-c[j])+s*(c[n]-c[j]));
cout<<f[n];
return ;
}

 

3、最大的算式(bigexp)

时间:2018-05-01

Description

给出N个数字,不改变它们的相对位置,在中间加入K个乘号和N-K-1个加号,(括号随便加)使最终结果尽量大。因为乘号和加号一共就是N-1个了,所以恰好每两个相邻数字之间都有一个符号。例如:

N=5, K=2,5个数字分别为1、2、3、4、5,可以加成:

1*2*(3+4+5)=24

1*(2+3)*(4+5)=45

(1*2+3)*(4+5)=45

……

Input

输入文件共有二行,第一行为两个有空格隔开的整数,表示N和K,其中(2<=N<=15, 0<=K<=N-1)。第二行为 N个用空格隔开的数字(每个数字在0到9之间)。

Output

输出文件仅一行包含一个整数,表示要求的最大的结果

最后的结果<=maxlongint

Sample Input

5 2
1 2 3 4 5
Sample Output
120

Solution:

  本题定义状态$f[i][j]$表示前$i$个数用了$j$个乘号的最大运算值(开始时前缀和处理,默认加法,等同于把加号变成乘号再左右两边加括号)。

  那么初始状态$f[i][0]=\sum{a[k]},k\in[1,i]$,目标状态$f[n][k]$,不难想出状态转移方程:$f[i][j]=max(f[i][j],f[p][j-1]*(f[i][0]-f[p][0])),\;p\in[1,i)$。

代码:

 #include<bits/stdc++.h>
#define Max(a,b) (a)>(b)?(a):(b)
#define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
using namespace std;
typedef long long ll;
const int N=;
ll n,k,f[N][N],a[N];
int main(){
ios::sync_with_stdio();
cin>>n>>k;
For(i,,n)cin>>a[i],a[i]+=a[i-],f[i][]=a[i];
For(i,,n) For(j,,i-) For(p,,i-)
f[i][j]=Max(f[i][j],f[p][j-]*(f[i][]-f[p][]));
cout<<f[n][k];
return ;
}

 4、字符串距离(blast)

时间:2018-05-02

Description

设有字符串X,我们称在X的头尾及中间插入任意多个空格后构成的新字符串为X的扩展串,如字符串X为”abcbcd”,则字符串“abcb□cd”,“□a□bcbcd□”和“abcb□cd□”都是X的扩展串,这里“□”代表空格字符。

如果A1是字符串A的扩展串,B1是字符串B的扩展串,A1与B1具有相同的长度,那么我扪定义字符串A1与B1的距离为相应位置上的字符的距离总和,而两个非空格字符的距离定义为它们的ASCII码的差的绝对值,而空格字符与其他任意字符之间的距离为已知的定值K,空格字符与空格字符的距离为0。在字符串A、B的所有扩展串中,必定存在两个等长的扩展串A1、B1,使得A1与B1之间的距离达到最小,我们将这一距离定义为字符串A、B的距离。

请你写一个程序,求出字符串A、B的距离。

Input

输入文件第一行为字符串A,第二行为字符串B。A、B均由小写字母组成且长度均不超过2000。第三行为一个整数K(1≤K≤100),表示空格与其他字符的距离。

Output

输出文件仅一行包含一个整数,表示所求得字符串A、B的距离。

Sample Input

cmc
snmn
2
Sample Output
10

Solution:

  本题一道普通$DP$。

  设$f[i][j]$表示匹配到$s1$的$i$位置和$s2$的$j$位置时的最小距离,初始状态$f[i][0]=f[i-1]+k$(表示$s1$第$i$个字符和空格匹配),同理$f[0][j]=f[0][j-1]+k$,目标状态$f[|s1|][|s2|]$。

  由题意易得,每次匹配只有三种情况:不加空格直接匹配$i,j$,$i$加空格即$i-1,j$匹配的基础上加$k$,$j$加空格即$i,j-1$匹配的基础上加$k$,取三者最小值即可。

  则状态转移方程:$f[i][j]=min(f[i-1][j-1]+abs(s1[i]-s1[j]),min(f[i][j-1]+k,f[i-1][j]+k))$

代码:

 #include<bits/stdc++.h>
#define il inline
#define Min(a,b) (a)<(b)?(a):(b)
#define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
using namespace std;
const int N=;
int l1,l2,k,f[N][N];
char s1[N],s2[N];
int main(){
scanf("%s%s%d",s1+,s2+,&k);
l1=strlen(s1+),l2=strlen(s2+);
memset(f,0x3f,sizeof(f));f[][]=;
For(i,,l1)f[i][]=f[i-][]+k;
For(i,,l2)f[][i]=f[][i-]+k;
For(i,,l1) For(j,,l2)
f[i][j]=Min(f[i-][j-]+abs(s1[i]-s2[j]),Min(f[i-][j]+k,f[i][j-]+k));
cout<<f[l1][l2];
return ;
}

5、书的复制(Book)

时间:2018-05-02

Description

现在要把m本有顺序的书分给k给人复制(抄写),每一个人的抄写速度都一样,一本书不允许给两个(或以上)的人抄写,分给每一个人的书,必须是连续的,比如不能把第一、第三、第四本书给同一个人抄写。

现在请你设计一种方案,使得复制时间最短。复制时间为抄写页数最多的人用去的时间。

Input

第一行两个整数m,k;(k≤m≤500)

第二行m个整数,第i个整数表示第i本书的页数。

Output

共k行,每行两个整数,第i行表示第i个人抄写的书的起始编号和终止编号。k行的起始编号应该从小到大排列,如果有多解,则尽可能让前面的人少抄写。

Sample Input

9 3
1 2 3 4 5 6 7 8 9
Sample Output
1 5
6 7
8 9

Solution:

  虽说这题名义上是$DP$,但是我还是无脑二分做了。直接二分答案,然后贪心判断,输出时直接递归输出就行了。

代码:

 #include<bits/stdc++.h>
using namespace std;
int m,k,l,r,mid,a[];
inline bool check(int x)
{
int tot=,num=;
for(int i=m;i>=;i--)
{
if(tot+a[i]<=x)tot+=a[i];
else tot=a[i],num++;
}
return num>=k;
}
inline void print(int m,int k,int x)
{
int s,q;
if(k==)return;
if(k==){printf("1 %d\n",m);return;}
s=,q=m;
while(s+a[q]<=x){s+=a[q];q--;}
print(q,k-,x);
printf("%d %d\n",q+,m);
}
int main()
{
scanf("%d%d",&m,&k);
for(int i=;i<=m;i++)scanf("%d",&a[i]),r+=a[i];
while(l<=r)
{
mid=l+r>>;
if(check(mid))l=mid+;
else r=mid-;
}
print(m,k,l);
return ;
}

 

6、公路乘车(busses)

时间:2018-05-03

Description

一个特别的单行街道在每公里处有一个汽车站。顾客根据他们乘坐汽车的公里使来付费。例如样例的第一行就是一个费用的单子。

没有一辆车子行驶超过10公里,一个顾客打算行驶n公里(1<=n<=100),它可以通过无限次的换车来完成旅程。最后要求费用最少。

Input

第一行十个整数分别表示行走1到10公里的费用(<=500)。注意这些数并无实际的经济意义,即行驶10公里费用可能比行驶一公里少。

第二行一个整数n表示,旅客的总路程数。

Output

仅一个整数表示最少费用。

Sample Input

12 21 31 40 49 5869 79 90 101

15

Sample Output

147

Solution:

  本题,直接是裸的完全背包问题,$f[i]$表示走$i$距离的最少花费,$f[i]=min(f[i],f[i-j]+w[j])$(注意枚举顺序),输出目标状态$f[n]$就$ok$了。

代码:

 #include<bits/stdc++.h>
#define Min(a,b) (a)>(b)?(b):(a)
#define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
using namespace std;
const int N=;
int w[],n,f[N];
int main(){
ios::sync_with_stdio();
memset(f,0x3f,sizeof(f));f[]=;
For(i,,)cin>>w[i];cin>>n;
For(i,,) For(j,i,n) f[j]=Min(f[j],f[j-i]+w[i]);
cout<<f[n];
return ;
}

7. 积木城堡(Castle)

时间:2018-05-03

Description

XC的儿子小XC最喜欢玩的游戏用积木垒漂亮的城堡。城堡是用一些立方体的积木垒成的,城堡的每一层是一块积木。小XC是一个比他爸爸XC还聪明的孩子,他发现垒城堡的时候,如果下面的积木比上面的积木大,那么城堡便不容易倒。所以他在垒城堡的时候总是遵循这样的规则。

小XC想把自己垒的城堡送给幼儿园里漂亮的女孩子们,这样可以增加他的好感度。为了公平起见,他决定把送给每个女孩子一样高的城堡,这样可以避免女孩子们为了获得更漂亮的城堡而引起争执。可是他发现自己在垒城堡的时候并没有预先考虑到这一点。所以他现在要改造城堡。由于他没有多余的积木了,他灵机一动,想出了一个巧妙的改造方案。他决定从每一个城堡中挪去一些积木,使得最终每座城堡都一样高。为了使他的城堡更雄伟,他觉得应该使最后的城堡都尽可能的高。

任务:

请你帮助小XC编一个程序,根据他垒的所有城堡的信息,决定应该移去哪些积木才能获得最佳的效果。

Input

第一行是一个整数N(N<=100),表示一共有几座城堡。以下N行每行是一系列非负整数,用一个空格分隔,按从下往上的顺序依次给出一座城堡中所有积木的棱长。用-1结束。一座城堡中的积木不超过100块,每块积木的棱长不超过100。

Output

一个整数,表示最后城堡的最大可能的高度。如果找不到合适的方案,则输出0。

Sample Input

2
2 1 –1
3 2 1 –1
Sample Output

3

Solution:

  本题,开始时还看错题了,以为是求最长上升子序列(还调了2次,手动滑稽~)。

  那么一句话讲下本题题意,可以理解为就是$n$个背包,要求每个背包装出相同容量,求这个最大容量。

  于是每次跑一遍完全背包,然后记录一下能装出的容量。最后输出次数出现$n$次的最大容量。

代码:

 #include<bits/stdc++.h>
#define Max(a,b) (a)>(b)?(a):(b)
#define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
using namespace std;
const int N=;
int n,a[N],f[N],ans,m,c,t,q,s[N]; int main(){
ios::sync_with_stdio();
cin>>n;q=n;
while(n--){
m=;t=;
while(cin>>c&&c!=-){
m++;a[m]=c;t+=c;
}
memset(f,,sizeof(f));
f[]=;
For(i,,m) Bor(j,a[i],t)if(f[j-a[i]]&&!f[j])f[j]=f[j-a[i]],s[j]++;
}
Bor(i,,)if(s[i]==q){ans=i;break;}
cout<<ans;
return ;
}

8、筷子(chop)

时间:2018-05-03

Description

A先生有很多双筷子。确切的说应该是很多根,因为筷子的长度不一,很难判断出哪两根是一双的。这天,A先生家里来了K个客人,A先生留下他们吃晚饭。加上A先生,A夫人和他们的孩子小A,共K+3个人。每人需要用一双筷子。A先生只好清理了一下筷子,共N根,长度为T1,T2,T3,……,TN.现在他想用这些筷子组合成K+3双,使每双的筷子长度差的平方和最小。(怎么不是和最小??这要去问A先生了,呵呵)

Input

输入文件共有两行,第一行为两个用空格隔开的整数,表示N,K(1≤N≤100, 0<K<50),第二行共有N个用空格隔开的整数,为Ti.每个整数为1~50之间的数。

Output

输出文件仅一行。如果凑不齐K+3双,输出-1,否则输出长度差平方和的最小值。

Sample Input

10 1

1 1 2 3 3 3 4 6 10 20

Sample Output

5

Solution:

  本题首先贪心的想到,排序,然后相邻两个组合肯定比用其中一个和其它的组和要好,但是由于只要选$k$对,所以我们并不知道怎么选最优。

  于是在贪心的基础上进行$DP$,先排序,用$s[i]$表示第$i$根和第$i+1$根搭配的长度差平方,然后定义状态$f[i][j]$表示前$i$根中选了$j$对的长度差平方和的最小值,则每次转移$f[i][j]$时,只有两种情况:

  1、第$i-1$根不与第$i$根搭配,则在前$i-1$根中搭配$j$对,即$f[i][j]=f[i-1][j]$;

  2、第$i-1$根和第$i$根搭配,则$s[i-1]$加上前$i-2$根搭配$j-1$对的值,即$f[i][j]=f[i-2][j-1]+s[i-1]$。

  所以状态转移方程:$f[i][j]=min(f[i-1][j],f[i-2][j-1]+s[i-1])$。输出目标状态$f[n][k+3]$就$ok$了。

代码:

 #include<bits/stdc++.h>
#define Min(a,b) (a)>(b)?(b):(a)
#define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
using namespace std;
const int N=;
int n,k,t[N],f[N][N],s[N];
int main(){
ios::sync_with_stdio();
cin>>n>>k;k+=;
For(i,,n)cin>>t[i];
sort(t+,t+n+);
For(i,,n) s[i]=(t[i]-t[i+])*(t[i]-t[i+]);
memset(f,0x3f,sizeof(f));
For(i,,n)f[i][]=;
For(i,,n) For(j,,k)f[i][j]=Min(f[i-][j],f[i-][j-]+s[i-]);
cout<<f[n][k];
return ;
}

9、护卫队(Convoy)

时间:2018-05-04

Description

护卫车队在一条单行的街道前排成一队,前面河上是一座单行的桥。因为街道是一条单行道,所以任何车辆都不能超车。桥能承受一个给定的最大承载量。为了控制桥上的交通,桥两边各站一个指挥员。护卫车队被分成几个组,每组中的车辆都能同时通过该桥。当一组车队达到了桥的另一端,该端的指挥员就用电话通知另一端的指挥员,这样下一组车队才能开始通过该桥。每辆车的重量是已知的。任何一组车队的重量之和不能超过桥的最大承重量。被分在同一组的每一辆车都以其最快的速度通过该桥。一组车队通过该桥的时间是用该车队中速度最慢的车通过该桥所需的时间来表示的。问题要求计算出全部护卫车队通过该桥所需的最短时间值。

Input

输入文件第一行包含三个正整数(用空格隔开),第一个整数表示该桥所能承受的最大载重量(用吨表示);第二个整数表示该桥长度(用千米表示);第三个整数表示该护卫队中车辆的总数(n<1000)。接下来的几行中,每行包含两个正整数W和S(用空格隔开),W表示该车的重量(用吨表示),S表示该车过桥能达到的最快速度(用千米/小时表示)。车子的重量和速度是按车子排队等候时的顺序给出的。

Output

输出文件应该是一个实数,四舍五入精确到小数点后1位,表示整个护卫车队通过该桥所需的最短时间(用分钟表示)。

Sample Input

100 5 10
40 25
50 20
50 20
70 10
12 50
9 70
49 30
38 25
27 50
19 70
Sample Output

75.0

Solution:

  我*~这题贼坑,提醒要开$long\;long$,然后就是初始化赋值要注意。。。(我错了几遍都是因为这个)

  首先,不难发现此题和任务安排那道$DP$类似。于是仿照那道题,定义状态$f[i]$表示到了前$i$辆车都通过桥的最少时间,则目标状态$f[n]$。

  转移时先赋初始状态$f[i]=f[i-1]+c/s[i]$($c$为长度,$s[i]$表示速度),注意一定要在循环中赋初值,因为每次$f[i-1]$的值会被更新。从后往前枚举当前$i$为结尾的一组的起点$j$(从后往前是为了便于记录$s[i]$即速度的最小值,也很好判断限制重量的条件,即时退出循环),不难得到状态转移方程:$f[i]=min(f[i],f[j-1]+)+\frac{c}{p}$(这不需要解释了)。

代码:

 #include<bits/stdc++.h>
#define Min(a,b) (a)>(b)?(b):(a)
#define Max(a,b) (a)>(b)?(a):(b)
#define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
using namespace std;
const int N=;
long long n,m,c,w[N];
double s[N],f[N],p; int main(){
cin>>m>>c>>n;
For(i,,n)cin>>w[i]>>s[i],w[i]=w[i]+w[i-];
For(i,,n){
p=s[i];f[i]=f[i-]+c/s[i];
Bor(j,,i-){
p=Min(p,s[j]);
if(w[i]-w[j-]>m)break;
f[i]=Min(f[i],f[j-]+c/p);
}
}
printf("%.1lf",f[n]*);
return ;
}

10、对话(dialog)

时间:

Description

从前有两个人,一个名为"one",另一个则叫"puton"。很奇怪,"one"除了称呼"puton"名字外,只对他说"out"和"output"两个单词;"puton"除了称呼"one"名字外,只对他说"in"和"input"两个单词。

最近人们在研究他们对话,但是,由于资料的混乱,其中可能有一些不是他们的对话。你的任务是鉴别一些句子,判断这些句子是否可能是他们的对话。(即,判断句子是否可以被划分成若干单词,这些单词只可以是"one"、"puton"、"out"、"output"、"in"和"input")。
输入n个字符串,长度不超过200,表示一句句子。如果可能是那两个人的对话,则输出”YES”;否则,输出”NO”。
Input
第一行一个整数n,表示一共有n句句子。
此后每行一个字符串,表示一句句子。
Output
n行,每行一个”YES”或”NO”,表示你的判断结果。
Sample Input
 6
 puton
 inonputin
 oneputonininputoutoutput
 oneininputwooutoutput
 outpu
 utput
Sample Output
 YES
 NO
 YES
 NO
 NO
 NO

Solution:

  然而我还没调出来(手动滑稽~)

11、DOLLARS(dollars)

时间:2018-05-06

Description

在以后的若干天里戴维将学习美元与德国马克的汇率。编写程序帮助戴维何时应买或卖马克或美元,使他从100美元开始,最后能获得最高可能的价值。

Input

输入文件的第一行是一个自然数N,1≤N≤100,表示戴维学习汇率的天数。

接下来的N行中每行是一个自然数A,1≤A≤1000。第i+1行的A表示预先知道的第i+1天的平均汇率,在这一天中,戴维既能用100美元买A马克也能用A马克购买100美元。

Output

输出文件的第一行也是唯一的一行应输出要求的钱数(单位为美元,保留两位小数)。

注意:考虑到实数算术运算中进位的误差,结果在正确结果0.05美元范围内的被认为是正确的,戴维必须在最后一天结束之前将他的钱都换成美元。

Sample Input

5
400
300
500
300
250
Sample Output

266.67

样例解释 (无需输出)

Day 1 ... changing 100.0000 美元= 400.0000 马克
Day 2 ... changing 400.0000 马克= 133.3333 美元
Day 3 ... changing 133.3333 美元= 666.6666 马克
Day 5 ... changing 666.6666 马克= 266.6666 美元

update:2017/08/18: 1样例正确答案为266.67

2已经把测试点1改成样例

3spj原先误差是0.01,按照题目要求,重新改为0.05

Solution:

  本题太水,直接贪心模拟就$OK$了。

代码:

 #include<bits/stdc++.h>
using namespace std;
int n,a[];double d=,m;
int main()
{
cin>>n;
for(int i=;i<=n;i++)cin>>a[i];
for(int i=;i<=n;i++)
{
d=max(d,m*/a[i]);
m=max(m,d*a[i]/);
}
printf("%.2lf",d);
return ;
}

12、最大约数和(max)

时间:2018-06-20

Description

选取和不超过S的若干个不同的正整数,使得所有数的约数(不含它本身)之和最大。

Input

输入一个正整数S。

Output

输出最大的约数之和。

Sample Input

11
Sample Output

9

说明

样例说明

取数字4和6,可以得到最大值(1+2)+(1+2+3)=9。

数据规模

S<=1000

Solution:

  本题数据较小。

  考虑预处理$1\rightarrow s$每个数的除开本身的约数和。

  然后就把每个数的大小当做体积,约数和当做价值,跑一下$0/1$背包就好了。

代码:

 #include<bits/stdc++.h>
#define il inline
#define ll long long
#define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)>(b)?(b):(a))
using namespace std;
const int N=;
int s,v[N],f[N],ans; int main(){
ios::sync_with_stdio();
cin>>s;
For(i,,s) For(j,,i>>) if(i%j==) v[i]+=j;
For(i,,s) Bor(j,,i) f[i]=Max(f[i],f[i-j]+v[j]);
For(i,,s) ans=Max(ans,f[i]);
cout<<ans;
return ;
}

 13、A+B Problem(and)

时间:2018-06-27

Description

·1+1=? 显然是2

·a+b=? 1001回看不谢

·哥德巴赫猜想 似乎已呈泛滥趋势

·以上纯属个人吐槽

·给定一个正整数n,求将其分解成若干个素数之和的方案总数。

Input

一行:一个正整数n

Output

一行:一个整数表示方案总数

Sample Input

7
Sample Output

3

说明

【样例解释】

7=7 7=2+5

7=2+2+3

【福利数据】

【输入】 20

【输出】 26

【数据范围及约定】

对于30%的数据 1<=n<=10

对于100%的数据,1<=n<=10^3

Solution:

  本题数据比较小?(答案竟然爆int)。

  首先,我们先筛出$1000$以内的素数,然后因为是要求某一个数用素数相加形式的方案数,每个素数可以选多次也可以不选,所以考虑写DP。

  那么直接套上完全背包的思路就好了。

  注意最后答案会爆int,所以要开long long。

代码:

 #include<bits/stdc++.h>
#define il inline
#define ll long long
#define For(i,a,b) for(int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(int (i)=(b);(i)>=(a);(i)--)
using namespace std;
const int N=;
ll n,prime[N+],cnt,f[N];
bool isprime[N+]; int main(){
ios::sync_with_stdio();
cin>>n;
For(i,,n){
if(!isprime[i]) prime[++cnt]=i;
for(int j=;j<=cnt&&prime[j]*i<=n;j++){
isprime[prime[j]*i]=;
if(i%prime[j]==)break;
}
}
f[]=;
For(i,,cnt) For(j,prime[i],n) f[j]+=f[j-prime[i]];
cout<<f[n];
return ;
}


三十道DP练习(持续更新)(pw:DP)的更多相关文章

  1. geotrellis使用(三十六)瓦片入库更新图层

    前言 Geotrellis 是针对大数据量栅格数据进行分布式空间计算的框架,这一点毋庸置疑,并且无论采取何种操作,其实都是先将大块的数据切割成一定大小的小数据(专业术语为瓦片),这是分治的思想,也是分 ...

  2. geotrellis使用(三十九)COG 写入更新

    前言 前面介绍过了如何在 ETL 的时候更新 Layer,使得能够在大数据量的时候完成 ETL 操作,同时前两篇文章也介绍了 COG 以及如何在 Geotrellis 中实现 COG 的读取.本文介绍 ...

  3. dp的林林总总(持续更新,dp骚气解法等等)

    写在前面: 本人dp较弱,所以总结了一些坑点,转化思路以供复习使用,勿喷,甚至一些不是dp的题(贪心等等)也会放在这. 每个点后面会有我自己的题解,如果没有链接,向下找第一个链接,可能会有多题. 1. ...

  4. Salesforce LWC学习(三十八) lwc下如何更新超过1万的数据

    背景: 今天项目组小伙伴问了一个问题,如果更新数据超过1万条的情况下,有什么好的方式来实现呢?我们都知道一个transaction只能做10000条DML数据操作,那客户的操作的数据就是超过10000 ...

  5. 【iCore3 双核心板】例程三十二:UART_IAP_ARM实验——更新升级STM32

    实验指导书及代码包下载: http://pan.baidu.com/s/1hrnLJwC iCore3 购买链接: https://item.taobao.com/item.htm?id=524229 ...

  6. 【iCore3 双核心板】例程三十四:U_DISK_IAP_ARM实验——更新升级STM32

    实验指导书及代码包下载: http://pan.baidu.com/s/1pKabR7P iCore3 购买链接: https://item.taobao.com/item.htm?id=524229 ...

  7. 【iCore3 双核心板】例程三十五:HTTP_IAP_ARM实验——更新升级STM32

    实验指导书及代码包下载: http://pan.baidu.com/s/1eRgzSPW iCore3 购买链接: https://item.taobao.com/item.htm?id=524229 ...

  8. 【iCore4 双核心板_ARM】例程三十五:HTTP_IAP_ARM实验——更新升级STM32

    实验现象: 核心代码: int main(void) { led.initialize(); //LED³õʼ»¯ key.initialize(); if(ARM_KEY_STATE == KEY ...

  9. 【iCore4 双核心板_ARM】例程三十四:U_DISK_IAP_ARM实验——更新升级STM32

    实验现象及操作说明: 1.本例程共有两个代码包,APP和IAP,IAP程序功能实现将APP程序升级至STM32中. 2.直接上电或烧写程序将执行升级的APP应用程序. 3.按下按键上电或写程序将进行升 ...

随机推荐

  1. java基础1.5版后新特性 自动装箱拆箱 Date SimpleDateFormat Calendar.getInstance()获得一个日历对象 抽象不要生成对象 get set add System.arrayCopy()用于集合等的扩容

    8种基本数据类型的8种包装类 byte Byte short Short int Integer long Long float Float double Double char Character ...

  2. MBProgressHUD 优雅地去提示

    项目主页: MBProgressHUD 实例下载: 点击下载 快速上手: 当执行需要较长时间的任务时,使用MBProgressHUD最重要的一点是: 保证主线程是空闲的,这样可以使UI实时更新.因此: ...

  3. 洛谷 P3372 线段树1

    这是一道模板题 线段树介绍https://www.cnblogs.com/nvwang123/p/10420832.html #include<bits/stdc++.h> using n ...

  4. linux系统的启动过程简要分析

    接触linux系统运维已经好几年了,常常被问到linux系统启动流程问题,刚好今天有空来梳理下这个过程:一般来说,所有的操作系统的启动流程基本就是: 总的来说,linux系统启动流程可以简单总结为以下 ...

  5. js延迟加载的方式有哪些?

    共有:defer和async.动态创建DOM方式(用得最多).按需异步载入js defer属性:(页面load后执行) HTML 4.01 为 <script>标签定义了 defer属性. ...

  6. 最短路径之迪杰斯特拉算法(Java)

    1)Dijkstra算法适用于求图中两节点之间最短路径 2)Dijkstra算法设计比较巧妙的是:在求源节点到终结点自底向上的过程中,源节点到某一节点之间最短路径的确定上(这也是我之前苦于没有解决的地 ...

  7. 残留的linux相关笔记

    1. 设置网络环境1) 设置宿主机网络环境#ifconfig eth1 192.168.16.111 2) 设置开发板网络环境>pri>setenv ipaddr 192.168.16.2 ...

  8. 第二章习题 C++

    1.编写一个程序,显示您的姓名和地址. #include<iostream> using namespace std; int main() { ]; cout << &quo ...

  9. (洛谷)P2709 小B的询问

    题目描述 小B有一个序列,包含N个1~K之间的整数.他一共有M个询问,每个询问给定一个区间[L..R],求Sigma(c(i)^2)的值,其中i的值从1到K,其中c(i)表示数字i在[L..R]中的重 ...

  10. 解决Android Studio报错:DefaultAndroidProject : Unsupported major.minor version 52.0

    解决办法是你需要将工程根目录build.gradle中的 classpath 'com.android.tools.build:gradle:2.2.0' 更改成 classpath 'com.and ...