# 6 happy dp (Beginner Level 1)

 expect actual Difference a 100 83 -17 b 100 100 0 c 100 100 0 d 100 100 0 e 0 0 0 f 100 100 0 g 100 67 -33 (no spaces between sample numbers) h 100 0 -100 i 0 0 0 j 100 0 0 the sum 800 400 -400

## a. Stone merging

From the meaning of the question, we can easily get the dp transfer equationThe maximum value is the same

Sum is the prefix sum. If it is not a ring, it isefficiency

Method 1: enumerate breakpoints

From a point of disconnection to a chain to do efficiencyFang, this question can be passed

Method 2: double length ring

Disconnect from any point and copy to the endtoo

```#include<bits/stdc++.h>
using namespace std;
int f[205][205],a[205],sum[205];//Remember to drive twice
int g[205][205];
int an1=0x7f7f7f7f,an2;
int n;
int main(){
scanf("%d",&n);
memset(f,0x3f,sizeof(f));
for(int i=1;i<=n;i++){
scanf("%d",a+i);
a[i+n]=a[i];
}
for(int i=1;i<=n*2;i++){
sum[i]=sum[i-1]+a[i];
f[i][i]=0;
}
for(int len=2;len<=n;len++){
for(int i=1;i+len-1<n*2;i++){
int j=i+len-1;
for(int k=i;k<j;k++){
f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]+sum[j]-sum[i-1]);
g[i][j]=max(g[i][j],g[i][k]+g[k+1][j]+sum[j]-sum[i-1]);
}
}
}
for(int i=1;i<=n;i++){
an1=min(an1,f[i][i+n-1]);
an2=max(an2,g[i][i+n-1]);
}
printf("%d\n%d",an1,an2);
}
/*
6 6 5 4 2 3 4

*/ ```

## b. Match

Enumerate each number, select or deselect, butIf you want to bomb, you should consider half deep search. Specifically, enumerate the possible situations of the first halfRecord the situation and the number of sum. In the second half of the enumeration, add ans, half is

Half of the total is also recorded by the other half of each case, and the answer should be divided by 2;

```#include<bits/stdc++.h>
using namespace std;
int f[50000],a[55];
int n,sum,ans,half;
inline void dfs(int x,int s){
if(s>sum) return ;
if(x>half){
f[s]++;
return ;
}
dfs(x+1,s);
dfs(x+1,s+a[x]);
}
inline void dfs2(int x,int s){
if(s>sum) return ;
if(x>n){
ans+=f[sum-s];
return ;
}
dfs2(x+1,s);
dfs2(x+1,s+a[x]);
}
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",a+i);
sum+=a[i];
}
if(sum&1){
cout<<0;
return 0;
}
sum/=2;
half=n/2;
dfs(1,0);
dfs2(half+1,0);
cout<<ans/2;
}
/*
7
1 2 3 4 5 6 7

*/```

## c. Lecture hall arrangement

Sort first without saying anything. The left endpoint is the first keyword and the right endpoint is the second keyword

Then consider the transfer equation,It means that it ends with scene i, that is, scene i must give a speech

And thenYes

```#include<bits/stdc++.h>
using namespace std;
struct node{
int l,r;
}p[5050];
bool operator < (node x,node y){
return x.l<y.l || x.l==y.l && x.r<y.r;
}
int n,ans;
int f[5050];
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d%d",&p[i].l,&p[i].r);
sort(p+1,p+n+1);
for(int i=1;i<=n;i++)
for(int k=0;k<i;k++)
if(p[k].r<=p[i].l)
f[i]=max(f[i],f[k]+p[i].r-p[i].l);
ans=max(ans,f[i]);
cout<<ans;
}```

## d. Pass a note

Enumerate the possible transfer conditions of each point. Note that the two routes of the current point and the previous point cannot coincide

```#include<bits/stdc++.h>
using namespace std;
const int N=56;
int n,m,a[N][N],f[N<<1][N][N];
int main(){
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]);
for(int i=0;i<n+m-3;i++)
for(int j=1;j<=n && j<=i+1;j++)
for(int k=1;k<=n && k<=i+1;k++){
if(j!=k){
f[i+1][j][k]=max(f[i+1][j][k],f[i][j][k]+a[j][i+3-j]+a[k][i+3-k]);
f[i+1][j+1][k+1]=max(f[i+1][j+1][k+1],f[i][j][k]+a[j+1][i+2-j]+a[k+1][i+2-k]);
}
if(j+1!=k) f[i+1][j+1][k]=max(f[i+1][j+1][k],f[i][j][k]+a[j+1][i+2-j]+a[k][i+3-k]);
if(k+1!=j) f[i+1][j][k+1]=max(f[i+1][j][k+1],f[i][j][k]+a[j][i+3-j]+a[k+1][i+2-k]);
}
cout<<f[n+m-3][n-1][n]<<endl;
return 0;
}
/*
3 3
0 3 9
2 8 5
5 7 0

*/```

## e. The escape of the catcher

Speak the code directly

```#include<bits/stdc++.h>
using namespace std;
int m,s,t,now=0;
int main() {
cin>>m>>s>>t;
int s1=0,s2=0;
for(int i=1; i<=t; i++) {
s1+=17;//See if it's walking or flashing
if(m>=10) {//Flash when there is blue
s2+=60;
m-=10;
}
else m+=4;//No blue, go back to blue
if(s2>s1) s1=s2;//If the flash is good, the walking time in front is not as good as all the flash
if(s1>s) {
cout<<"Yes"<<endl<<i<<endl;
return 0;
}
}
cout<<"No"<<endl<<s1<<endl;
}```

## f. Matrix access game

Obviously, each row will not affect other rows, so it is set for each rowIndicates that the number of i to j left has not been taken away

Available

```#include<bits/stdc++.h>
#define N 40
using namespace std;
const int mm=10;
struct A {
int e[N];
A(int x=0):e() {
for (int i=x; i; i/=10) e[++e[0]]=i%10;
if (!e[0]) e[0]++;
}
e[0]=0;
char c=getchar();
while (c<=32) c=getchar();
while (c>32) {
e[++e[0]]=c-'0';
c=getchar();
}
reverse(e+1,e+e[0]+1);
}
void print() {
for (int i=e[0]; i>=1; i--) printf("%d",e[i]);
printf("\n");
}
};
A operator + (const A &a,const A &b) {
A c;
c.e[0]=max(a.e[0],b.e[0]);
for (int i=1; i<=c.e[0]; i++) {
c.e[i]+=a.e[i]+b.e[i];
c.e[i+1]+=c.e[i]/mm;
c.e[i]%=mm;
}
if (c.e[c.e[0]+1]) c.e[0]++;
return c;
}
A operator * (const A &a,const A &b) {
A c;
c.e[0]=a.e[0]+b.e[0];
for (int i=1; i<=a.e[0]; i++)
for (int j=1; j<=b.e[0]; j++) {
c.e[i+j-1]+=a.e[i]*b.e[j];
c.e[i+j]+=c.e[i+j-1]/mm;
c.e[i+j-1]%=mm;
}
while (c.e[0]>1&&!c.e[c.e[0]]) c.e[0]--;
return c;
}
bool operator < (const A &a,const A &b) {
if (a.e[0]!=b.e[0]) return a.e[0]<b.e[0];
for (int i=a.e[0]; i>=1; i--)
if (a.e[i]!=b.e[i]) return a.e[i]<b.e[i];
return 0;
}
bool operator > (const A &a,const A &b) {
return b<a;
}

A f[90][90];
A p[81];
A a[81][81];
int n,m;
A ans;
int main() {
p[1].e[1]=2;
p[1].e[0]=1;
A zero;zero.e[0]=1,zero.e[1]=0;
ans=zero;
for(int i=1;i<=80;i++)	p[i+1]=p[i]*p[1];
cin>>n>>m;
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
for(int i=1;i<=n;i++){
for(int len=m;len;len--){
for(int l=1;l+len-1<=m;l++){
int r=l+len-1;
f[l][r]=zero;
if(l>1){
A q=f[l-1][r]+a[i][l-1]*p[m-len];
if(f[l][r]<q)
f[l][r]=q;
}
if(r<m){
A q=f[l][r+1]+a[i][r+1]*p[m-len];
if(f[l][r]<q)
f[l][r]=q;
}
}
}
A maxx=zero;
for(int j=1;j<=m;j++){
A q=f[j][j]+a[i][j]*p[m];
if(q>maxx)
maxx=q;
}
ans=maxx+ans;
}
ans.print();
return 0;
}
```

## g. Urban transportation

Reverse thinking: if you want to get from city 1 to city 11, you can only transfer from city 8, 9 or 10. If you know the shortest distance from city 1 to cities 8, 9 and 10, just add the three shortest distances respectively to the distance between the three cities and city 11, and then take a minimum value. In this way, the problem becomes to find the shortest distance from city 1 to city 8, 9 and 10. These three sub problems are completely consistent with the original problem, but the scale of the problem is reduced a little. How to find the shortest distance from city 1 to city 8? The idea is the same as just now. If you know the shortest distance from city 1 to cities 4 and 5, the shortest distance to city 8 is the smaller of the shortest distance to city 4 plus 5 and the shortest distance to city 5 plus 5. How to find the shortest distance between cities 4 and 5 This continues until the shortest distance from city 1 to cities 2 and 3 is found, and this value is known (because there is a direct edge connection between cities 1 and 2.3)

```#include<bits/stdc++.h>
using namespace std;
int f[111];
int a[111][111];
int n;
char c;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
scanf("%d",&a[i][j]);
}
f[i]=0x3f3f3f3f;
}
f[n]=0;
for(int i=n-1;i;i--)
for(int j=i+1;j<=n;j++)
if(a[i][j] && f[j]!=0x3f3f3f3f)
f[i]=min(f[i],a[i][j]+f[j]);
cout<<f[1];

}
/*
11
0 5 3 0 0 0 0 0 0 0 0
5 0 0 1 6 3 0 0 0 0 0
3 0 0 0 8 0 4 0 0 0 0
0 1 0 0 0 0 0 5 6 0 0
0 6 8 0 0 0 0 5 0 0 0
0 3 0 0 0 0 0 0 0 8 0
0 0 4 0 0 0 0 0 0 3 0
0 0 0 5 5 0 0 0 0 0 3
0 0 0 6 0 0 0 0 0 0 4
0 0 0 0 0 8 3 0 0 0 3
0 0 0 0 0 0 0 3 4 3 0

*/```

## h. Longest common subsequence

Ultimate board question

Define the state f[i][j], which represents the longest common subsequence length of the first I elements of sequence X and the first j elements of sequence Y. The state transition equation is

The time complexity of the above algorithm is 0 (len1, xlen2), which is already better. Can the spatial complexity be optimized? The method similar to Yang Hui triangle can be adopted. The "rolling" array is used to store the current row and the previous row respectively by using two - dimension groups for iterative storage.

```#include<bits/stdc++.h>
using namespace std;
int f[2][5050];
int main(){
char a[5050],b[5050];
scanf("%s",a);
scanf("%s",b);
int la=strlen(a),lb=strlen(b);
for(int i=1;i<=la;i++){
for(int j=1;j<=lb;j++){
if(a[i-1]==b[j-1]) f[i&1][j]=f[(i-1)&1][j-1]+1;
else f[i&1][j]=max(f[i&1][j-1],f[(i-1)&1][j]);
}
}
cout<<f[la&1][lb];
}```

## i. Toy packing

Positive solution slope optimization, butThe optimization can be passed, and the transfer equation is as follows

Optimization: record the maximum j that can update method dp(i) every time, and open the enumeration breakpoint from j for dp(i+1);

```#include<bits/stdc++.h>
using namespace std;
long long dp[50010],sum[50010],a[50010];
long long L;
int n;
int main(){
scanf("%d%lld",&n,&L);
for(int i=1;i<=n;i++){
scanf("%lld",a+i);
sum[i]=sum[i-1]+a[i];
}
for(int i=1,k=0;i<=n;i++){
dp[i]=1e18;
for(int j=k;j<i;j++){
if(dp[j]+(sum[i]+i-sum[j]-j-L-1)*(sum[i]+i-sum[j]-j-L-1)<=dp[i]){
dp[i]=dp[j]+(sum[i]+i-sum[j]-j-L-1)*(sum[i]+i-sum[j]-j-L-1);
k=j;
}
}
}
cout<<dp[n];
}```

The reason may be that the unit length is increased by at least two for each increase. For two boxes of items containing the same section, the difference is at least two, plus square. Even if the previous point is wrong, it is covered by the correct decision later

Of course, it is possible that this practice is indeed correct, but I am too weak to prove

Slope optimization... Didn't learn!!!

## j. Longest common ascending subsequence

The combination of the two boards, but the difficulty increases a lot

F[i,j] indicatesAndCan formLength of LCIS ending with. It may be assumed that

WhenF[i,j]=F[i-1,j]

WhenWhen, yes

During the transfer process, theThe set composed of k is called the decision set when F[i,j] performs state transition, which is recorded as S(i,j). Note that when the second layer cycle j increases from 1 to m, the first layer cycle i is a fixed value, which makes the condition

It's fixed. Therefore, when the local variable j increases by 1, the value range of k ranges fromBecomeThat is, the integer j may enter a new decision set, that is, we only need to check the condition O(1)If yes, the number already in the decision set will not be removed:

Therefore, the above transfer equation can be solved only by two-layer circulation. The ultimate goal is.

```for (int i = 1; i <= n; i++) {
// val is the maximum value of f[i-1][k] in the decision set S(i,j)
int val = 0;
// When j=1, 0 can be taken as the value of k
if (b[0] < a[i]) val = f[i - 1][0];
for (int j = 1; j <= m; j++) {
if (a[i] == b[j]) f[i][j] = val + 1;
else f[i][j] = f[i - 1][j];
// J is about to increase to j+1. Check whether J can enter the new decision set
if (b[j] < a[i]) val = max(val, f[i - 1][j]);
}
}```

Conclusion: most of them are quite basic, but the reason for the large difference is that they don't pay attention to the scope

Posted on Mon, 06 Sep 2021 19:17:48 -0400 by Guldstrand