[大山中学dp常练-4 Rounds]

Round#1 2016.9.28

这次晚练十分sb 有点浪费时间 全是dp题

先说过程 3分钟草了第一题之后感觉好像有点水 然后翻了翻题目 看了看第一第四题两颗星 其他三颗星 然后一下子第二题题目太长就兴起草第三题 打了四十五分钟然后草第二题 然后就没了要收卷(第二题还没调完 给多我五分钟就A了) 整体用了一个半小时吧(马力有点弱..)

三维dp 你也可以变成N和K的dp只是麻烦一点 这题不会可以退役

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
#define Maxn 1010
using namespace std;
int F[Maxn][40][2]; int T[Maxn];
int main()
{
  freopen("bcatch.in","r",stdin);
  freopen("bcatch.out","w",stdout);
  int N,K; scanf("%d%d",&N,&K); for(int i=1;i<=N;i++) scanf("%d",&T[i]);
  for(int i=1;i<=N;i++)
  {
    for(int j=0;j<=K;j++)
    {
      F[i][j][0]=max(F[i][j][0],max(F[i-1][j][0],F[i-1][j-1][1])+(T[i]==1));
      F[i][j][1]=max(F[i][j][1],max(F[i-1][j][1],F[i-1][j-1][0])+(T[i]==2));
    }
  }
  int maxx=0;
  for(int i=0;i<=K;i++) for(int j=0;j<=1;j++) maxx=max(maxx,F[N][i][j]);
  return printf("%d
",maxx),0;
}
/*
7
2
1
1
2
2
1
1
*/
View Code

第二题题目很烦 条件很多 我们发现斜坡是越短越好 然后用时间和能力值dp一下随便草就好了

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<cmath>
using namespace std;
struct Course
{
  int m,l,a;
}C[110];
bool Cmp(const Course &x,const Course &y){return x.m<y.m;}
struct XP
{
  int c,d;
}X[100010];
int T,S,N;
int F[10010][110];

int L[110];
int main()
{
  freopen("ski.in","r",stdin);
  freopen("ski.out","w",stdout);
  scanf("%d%d%d",&T,&S,&N);
  for(int i=1;i<=S;i++) scanf("%d%d%d",&C[i].m,&C[i].l,&C[i].a);
  sort(C+1,C+S+1,Cmp);
  for(int i=1;i<=N;i++) scanf("%d%d",&X[i].c,&X[i].d);
  
  for(int i=0;i<=100;i++) L[i]=10000;
  for(int i=1;i<=N;i++) L[X[i].c]=min(L[X[i].c],X[i].d);
  for(int i=1;i<=100;i++) L[i]=min(L[i],L[i-1]);
  
  for(int i=0;i<=T;i++) for(int j=0;j<=100;j++) F[i][j]=-1;
  F[0][1]=0; int l=1; int r=1;
  for(int i=0;i<=T;i++)
  {
    while(C[r].m==i) r++;
    for(int j=0;j<=100;j++)
    {
      if(F[i][j]!=-1)
      {
        F[i+1][j]=max(F[i+1][j],F[i][j]);
        if(i+L[j]<=T) F[i+L[j]][j]=max(F[i+L[j]][j],F[i][j]+1);
        for(int k=l;k<r;k++) if(i+C[k].l<=T) F[i+C[k].l][C[k].a]=max(F[i+C[k].l][C[k].a],F[i][j]);
      }
    }
    l=r;
  }
  int maxx=0;
  for(int i=1;i<=T;i++) for(int j=1;j<=100;j++) maxx=max(maxx,F[i][j]);
  return printf("%d
",maxx),0;
}
/*
10 1 2
3 2 5
4 1
1 3
*/
View Code

第三题也想了一会儿 我们发现有一些状态我们是一定到不了的 就好比

7 3

8 5

其实8的时候最多为4 就改一下 还有一种

7 3

8 1

那么你7是要改成2的

先从后面扫一遍 然后前面再扫一遍到后面(先后顺序不知道可不可以换 应该可以吧 考场上没多想)

剩下的话都是可以到的 然后每次都到这个速度就是最优的因为你如果合法 但是又小于这个速度就是最差的 那么的话每两个点之间你就把它们先升到一个高度然后再往上飞最长的一段再下来

最后还要判断一下到终点 (就这样没了两个点)

#include<cstdio>
#include<iostream>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#define Maxn 100010
using namespace std;
bool Cmp(const pair<int,int> &x,const pair<int,int> &y){if(x.first!=y.first) return x.first<y.first; return x.second>y.second;}
int L,M; pair<int,int>pr[Maxn];
int F[Maxn];
int main()
{
  freopen("bobsled.in","r",stdin);
  freopen("bobsled.out","w",stdout);
  scanf("%d%d",&L,&M); for(int i=1;i<=M;i++) scanf("%d%d",&pr[i].first,&pr[i].second);
  sort(pr+1,pr+M+1,Cmp); memset(F,63,sizeof(F)); F[0]=1;
  for(int i=1;i<=M;i++) F[i]=min(F[i],pr[i].second);
  for(int i=M;i>=1;i--)
  {
    if(pr[i].first!=pr[i+1].first)
    {
      F[i]=min(F[i],F[i]+(F[i+1]-F[i])+(pr[i+1].first-pr[i].first));
    }        
    else F[i]=F[i+1];
  } int l;
  for(int i=1;i<=M;i=l+1)
  {
    l=i; while(pr[l].first==pr[l+1].first) l++;
    if(pr[l].first!=pr[i-1].first)
    {
      F[l]=min(F[l],F[l]+((F[i-1]-F[l])+(pr[l].first-pr[i-1].first)));
    }
    for(int j=i;j<=l;j++) F[j]=F[l];
  }
  
  int ans=0;
  for(int i=1;i<=M;i++) ans=max(ans,max(F[i],F[i-1])+(pr[i].first-pr[i-1].first-abs(F[i]-F[i-1]))/2);
  ans=max(ans,F[M]+(L-pr[M].first));
  return printf("%d
",ans),0;
}

/*
14 3
7 3
11 1
13 8
*/
View Code

看看范围 好像直接背包会爆 很明显这道题给出来的做法一定是NM 然后想想背包可不可以换种方式

看到都是M的倍数 也就是说 M以上的都可以变成小于M咯 其它也要保留一下 然后F[N][i]表示现在放到第I个物品 然后M的倍数+i 然后再用一个数组辅助转移搞一下就好了 差不多绕圈的dp

#include<cstdio>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#define Maxn 2010
using namespace std;
const int Mod=1e8;
int N,M; int A[Maxn]; int F[Maxn]; bool bo[Maxn]; int G[Maxn];
int main()
{
  freopen("fristeam.in","r",stdin);
  freopen("fristeam.out","w",stdout);
  scanf("%d%d",&N,&M);
  for(int i=1;i<=N;i++) scanf("%d",&A[i]);
  memset(F,0,sizeof(F)); F[0]=1; memset(G,0,sizeof(G)); memset(bo,0,sizeof(bo)); bo[0]=1;
  for(int i=1;i<=N;i++)
  {
    for(int j=0;j<M;j++) G[j]=0;
    for(int j=0;j<M;j++)
      if(bo[j]) G[(j+A[i])%M]=(G[(j+A[i])%M]+F[j])%Mod,bo[(j+A[i])%M]=1;
    for(int j=0;j<M;j++)
      if(bo[j]) F[j]=(F[j]+G[j])%Mod;
  }
  return printf("%d
",F[0]-1),0;
}
/*
4 5
1
2
8
2
*/
View Code

Round #2 2016.9.29

这次题目好像上了点难度,有点意思了

 第一题考场上看错题意 以为中间有一个高的就不能跨过去 其它都可以..

当我back回的时候 才发现那条线要是直的 所以的话用斜率搞一下 画画图 很容易把O(N^3)变成O(N^2)

有空再更..

原文地址:https://www.cnblogs.com/wohenshuai/p/5916042.html