暑期集训第二天(6-23)题解及总结

今天已经是集训的第二天了,今天的考试主要考了区间DP,其实这一段我并不很熟。

其实这是我第二遍写这篇博客了,原来那篇被某邹姓少年弄没了,我只好再写一遍了。

PART ONE:DP复习二:

 其实这道题在上午的时候我写出来了。只是我用的是暴搜,可能数据比较水就让我过了,但是其实这道题的正解我是不会写的,于是就在这里补一下吧,其实我感觉暴搜在DP这里的应用领域还是挺广的,包括昨天和今天好多题我都是用暴搜做的,还过了不少。但是从今天下午开始暴搜的应用就不怎么广了,好几道题都是只能得到一半左右的分数

方法一: 暴搜,用dfs的三个变量分别表示当前所处理到的位数,当前所分成的段数量及此时的乘积,暴搜的思路挺好想的,就是看数据,特别容易超时,所以最好慎用。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 const int N=5e1+10;
 5 #define int long long
 6 using namespace std;
 7 int len,a[N],b[N],pos[N],dp[N][N],score[N][N],g[N][N];
 8 int ans2[N],t[N],Max=-1;
 9 void dfs(int now,int m,int ans){
10     if(now>len+1 || m<0) return;
11     if(now==len+1&&m==0){
12         if(ans>Max){
13             Max=ans;
14             for(int i=0;i<=t[0];++i)
15                 ans2[i]=t[i];
16         }
17     }
18     for(int i=now;i<=len;++i){
19         t[++t[0]]=score[now][i];
20         dfs(i+1,m-1,ans*score[now][i]);
21         t[0]--;
22     }
23 }
24 void Solve(){
25     memset(dp,0,sizeof(dp));
26     memset(score,0,sizeof(score));
27     memset(g,0,sizeof(g));
28     memset(t,0,sizeof(t));
29     Max=-1;
30     len=0;
31     int num,m;
32     scanf("%lld%lld",&num,&m);
33     while(num){
34         b[++len]=num%10;
35         num/=10;
36     }
37     for(int i=1;i<=len;++i) pos[len-i+1]=b[i];
38     for(int i=1;i<=len;++i)
39         for(int j=i;j<=len;++j)
40             for(int k=i;k<=j;++k){
41                 score[i][j]*=10;
42                 score[i][j]+=pos[k];
43                 g[i][i]=pos[i];
44             }
45     dfs(1,m,1);
46     printf("%lld
",Max);
47     for(int i=1;i<=ans2[0];++i) printf("%lld ",ans2[i]);
48 }
49 signed main(){
50     int T;
51     scanf("%lld",&T);
52     while(T--) Solve();
53     return 0;
54 }
整数划分方法一

方法二: 正解DP,用f[i][j]表示前i位数字分为j段的答案,这其实就是一个区间DP板子的变形,我们很容易想到转移方程f[i][j]=max(f[i][j],f[k][j-1]*a[k+1][i])(a数组存储区间内的数字段),之后就是注意要用递归来处理答案的第二部分,就没有什么了。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<algorithm>
 5 #include<cmath>
 6 using namespace std;
 7 const int maxn=2e2+50,INF=0x3f3f3f3f;
 8 int n,sum[maxn],m,g[maxn][maxn],path[maxn],ans;
 9 unsigned long long f[maxn][maxn],a[maxn][maxn];
10 char str[maxn];
11 inline int read(){
12     int s=0,w=1;
13     char ch=getchar();
14     while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
15     while(ch>='0'&&ch<='9')s=s*10+ch-'0',ch=getchar();
16     return s*w;
17 }
18 void print(int i,int j){
19     if(!g[i][j]||j==0)return;
20     path[++ans]=g[i][j];
21     print(g[i][j],j-1);
22 }
23 int main(){
24     int T=read();
25     while(T--){
26         memset(f,0,sizeof(f));
27         memset(path,0,sizeof(path));
28         memset(g,0,sizeof(g));
29         memset(a,0,sizeof(a));
30         ans=0;
31         scanf("%s",str+1);
32         m=read();
33         n=strlen(str+1);
34         if(m==1){cout<<str+1<<endl<<str+1<<endl;continue;}
35         else if(m>n){cout<<0<<endl<<0<<endl;continue;}
36         for(int i=1;i<=n;i++)a[i][i]=str[i]-'0';
37         for(int i=1;i<=n;i++){
38             for(int j=i+1;j<=n;j++){
39                 a[i][j]=a[i][j-1]*10+a[j][j];
40             }
41         }
42         f[0][0]=1;
43         for(int i=1;i<=n;i++){
44             for(int j=1;j<=min(i,m);j++){
45                 for(int k=j-1;k<i;k++){
46                     if(f[i][j]<f[k][j-1]*a[k+1][i]){
47                         f[i][j]=f[k][j-1]*a[k+1][i];
48                         g[i][j]=k;
49                     }
50                     
51                 }
52             }
53         }
54         cout<<f[n][m]<<endl;
55         print(n,m);
56         sort(path+1,path+m+1);
57         int now=1;
58         if(f[n][m]==0){
59             for(int i=1;i<m;i++){
60                 cout<<a[i][i]<<" ";
61             }
62             if(a[m][n]==0){
63                 for(int i=1;i<=n-now;i++)cout<<0;
64             }
65             cout<<endl;
66         }
67         else {
68             for(int i=1;i<m;i++){
69                 cout<<a[path[i]+1][path[i+1]]<<" ";
70                 now=path[i+1];
71             }
72             if(a[now+1][n]==0){
73                 for(int i=1;i<=n-now-1;i++)cout<<0;
74             }
75             cout<<a[now+1][n]<<endl;
76         }
77     }
78 }
整数划分方法二

 

 

 

 推荐博客:https://www.cnblogs.com/fengwu2005/p/11289562.html

这道题和其他区间DP的区别主要在那个存在负值上,我们在一般区间dp的二维上加开第三维,来表示当前的值是最大还是最小,如果我们计算的是加法,直接大大得大小小得小就行了,但是在计算乘法时由于存在负负得正,在计算两个区间的合并时需要将两个区间的大,小值的四种情况分别计算,再取其最大,最小,就可以了。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstdlib>
 4 #include<cstring>
 5 #include<algorithm>
 6 using namespace std;
 7 int n,shu[150],f[150][150][3],sum[150][150],ff[150]={0},ma,mb,a,b,c,d;
 8 char fu[150];
 9 int main()
10 {
11     scanf("%d",&n);
12     for(int i=1;i<=n;i++){
13         scanf(" %c%d",&fu[i],&shu[i]);
14     }
15     for(int i=n+1;i<=2*n;i++){
16         shu[i]=shu[i-n];
17         fu[i]=fu[i-n];
18     }
19     for(int i=1;i<=n;i++){
20         for(int o=1;o<=2*n;o++){
21             for(int p=1;p<=2*n;p++){
22                 f[o][p][1]=-9999999;
23                 f[o][p][2]=9999999;
24             }
25         }
26         for(int q=1;q<=2*n;q++){
27             f[q][q][1]=shu[q];
28             f[q][q][2]=shu[q];
29         }
30         for(int l=2;l<=n;l++){
31             for(int j=i;j<=i+n-l;j++)
32             {
33                 int k=j+l-1;
34                 for(int x=j;x<k;x++){
35                     if(fu[x+1]=='t'&&f[j][k][1]<f[j][x][1]+f[x+1][k][1])f[j][k][1]=f[j][x][1]+f[x+1][k][1];
36                     if(fu[x+1]=='t'&&f[j][k][2]>f[j][x][2]+f[x+1][k][2])f[j][k][2]=f[j][x][2]+f[x+1][k][2];
37                     if(fu[x+1]=='x'){
38                         a=f[j][x][1]*f[x+1][k][1];
39                         b=f[j][x][2]*f[x+1][k][1];
40                         c=f[j][x][1]*f[x+1][k][2];
41                         d=f[j][x][2]*f[x+1][k][2];
42                         f[j][k][1]=max(max(max(a,b),max(c,d)),f[j][k][1]);
43                         f[j][k][2]=min(min(min(a,b),min(c,d)),f[j][k][2]);
44                     }
45                 }
46             }
47         }
48         ff[i]=f[i][i+n-1][1];
49     }
50     ma=-1000000;
51     for(int i=1;i<=n;i++){
52         if(ma<ff[i]){
53             ma=ff[i];
54             mb=i;
55         }
56     }
57     printf("%d
",ma);
58     for(int i=1;i<=n;i++){
59         if(ff[i]==ma){
60             printf("%d ",i);
61         }
62     }
63 }
多边形

洛谷P1220关路灯:

 

 这道题我们考虑,如果老张已经刚刚恰好关完了一个区间内的灯,那么他此时一定在区间的左边或右边,因为如果区间两边他都来过,那么他一定路过过区间中间的所有点,关灯又不耗时间,还省电直接断掉就行了,那么此时如果老张想要扩展这个区间,那么他有两种选择:向左或向右,而他此时的位置也有两种情况,即区间左端和区间右端,那么我们就有了四种情况进行转移,有了DP转移的思路这道题就好写了,老张有在左边向左,右边走,在右边向右,左边走四种情况,之后我们提前处理好每个区间之内的每段时间的花费,以方便我们转移,就可以了。

代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 const int N=50+5;
 5 using namespace std;
 6 int sum[N][N],cost[N],dp[N][N][2];
 7 struct Node{
 8     int loc,pow;
 9 }a[N];
10 int main(){
11     int n,m;
12     scanf("%d%d",&n,&m);
13     for(int i=1;i<=n;++i){
14         scanf("%d%d",&a[i].loc,&a[i].pow);
15     }
16     for(int i=1;i<=n;++i){
17         sum[i][i]=a[i].pow;
18         for(int j=i+1;j<=n;++j)
19             sum[i][j]=sum[i][j-1]+a[j].pow;
20     }
21     memset(dp,0x3f,sizeof(dp));
22     if(m>=2){
23         dp[m-1][m][0]=(a[m].loc-a[m-1].loc)*(sum[1][m-1]+sum[m+1][n]);
24     }
25     if(m<=n-1){
26         dp[m][m+1][1]=(a[m+1].loc-a[m].loc)*(sum[1][m-1]+sum[m+1][n]);
27     }
28     for(int len=3;len<=n;++len)
29         for(int l=1;l<=n-len+1;++l){
30             int r=l+len-1;
31             dp[l][r][0]=min(dp[l+1][r][0]+(a[l+1].loc-a[l].loc)*(sum[1][l]+sum[r+1][n]),dp[l+1][r][1]+(a[r].loc-a[l].loc)*(sum[1][l]+sum[r+1][n]));
32             dp[l][r][1]=min(dp[l][r-1][0]+(a[r].loc-a[l].loc)*(sum[1][l-1]+sum[r][n]),dp[l][r-1][1]+(a[r].loc-a[r-1].loc)*(sum[1][l-1]+sum[r][n]));
33         }
34     printf("%d
",min(dp[1][n][0],dp[1][n][1]));
35     return 0;
36 }
关路灯

PATR TWO :总结:

  其实这两天的题目还是比较温柔的,都比较简单,我一个暴力的思路水过了好多题,但是晚上教练指出我在做题的时候还存在诸多不足,我的效率还是很低的,另外,我的急性子的毛病还一直在,在做一道题的时候总是提交多次,思路不够缜密,总是在改完一个点后就匆匆地提交,AC了就完了,WA了就再找再提交,再集训还剩下的两周多的时间之内,我会尽力进行改正的,争取让自己在这段时间内完成属于自己的蜕变。 

原文地址:https://www.cnblogs.com/li-jia-hao/p/13184796.html