8.8&8.9 dp训练小结

写了两天的dp题,表示大多dp都不会啊,还是爆搜大法好。我真的太蒻了dp还是要多做题啊,一些基本的套路还是不熟,真正写对的dp也就一道,还一道爆搜过的,dp还有很深的坑要填啊。。

8.8

T1 质数和式

题意

20190809192703.png

大概就是给出一个数n,用质数将它表示按字典序由大到小排序,输出排列为k的质数和式

解析

20190809192841.png
20190809192853.png

代码(咕咕)

T2 终极简单问题

20190809192955.png

假的终极简单

解析

20190809193048.png

挂上学长的题解

代码(继续咕咕)

T3 分宝藏

题意

20190809193231.png
20190809193239.png

一道比较有趣的题,等有时间写吧。

20190809193159.png

20190809193326.png

代码(继续吧)

T4 取数字问题

题意

20190809193427.png

sb题目,不多说,爆搜就能过。

代码(这个总算没咕咕)

#include<bits/stdc++.h>
using namespace std;
int n,m,ans=1<<30,a[15][15];
void dfs(int x,int y,int data){
    if(x==n&&y==m){
        if(data>0){
            ans=min(ans,data);
            return;
        }
    }
    if(x+1<=n&&y<=m) dfs(x+1,y,data+a[x+1][y]);
    if(x<=n&&y+1<=m) dfs(x,y+1,data+a[x][y+1]);
}
int main(){
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;++i){
        for(int j=1;j<=m;++j){
            scanf("%d",&a[i][j]);
        }
    }
    dfs(1,1,a[1][1]);
    if(ans==(1<<30)) printf("-1");
    else printf("%d",ans);
    return 0;
}

正解据说是这样的

20190809193558.png

20190809193623.png

T5 求三角形最大的面积

题意

20190809193818.png
20190809193900.png
20190809193914.png

爆搜拿了40多分。。。

解析

20190809194005.png

代码(马上就补)

8.9

T1 可怜的绵羊

题意

20190809194248.png
20190809194257.png
20190809194307.png

一道比较神仙的题目,做法看解析吧,考场输出die个get 13 point

20190809194453.png

代码(还毛写,先放std)

#include <cstdio>
#include <cmath>
#include <cstring>
using namespace std;
#define maxn 101
 
struct point {
    long long x,y;
};
long long n,m=0;
//凸多边形顶点坐标和内部点的坐标
point vertex[maxn],insd[maxn];
//检查点是否在多边形边上
int out[maxn][maxn],online[maxn][maxn];
 
//默认的abs函数是对整数取绝对值
long long abs(long long x){
    return x<0 ? -x : x;
}
 
//返回三角形abc面积的两倍
long long area(point a,point b,point c){
    return abs(a.x*(b.y-c.y)+b.x*(c.y-a.y)+c.x*(a.y-b.y));
}
 
//向量oa叉乘向量ob
//大于0,这三个点是逆时针;小于0,这三个点是顺时针
long long multiple(point a,point b,point o){
    return (a.x-o.x)*(b.y-o.y)-(a.y-o.y)*(b.x-o.x);
}
 
void prepare(){
    long i,j,k,tmp;
    memset(out,0,sizeof(out));
    memset(online,0,sizeof(online));
    for (i=1;i<=n;i++)
        for (j=1;j<=n;j++)
            if (i!=j)
                for (k=1;k<=m;k++){
                    tmp=multiple(insd[k],vertex[j],vertex[i]);
                    if (tmp>=0) out[i][j]++; //判断是否在逆时针方向
                    if (tmp==0) online[i][j]=1;
                }
}
 
void dp(){
    long long u,i,j;
    long long a[maxn],tmp,max=0;
    //枚举点u,并求出最大值
    for (u=1;u<=n-2;u++){
        memset(a,0,sizeof(a));
        for (i=u+1;i<=n-1;i++)
            for (j=i+1;j<=n;j++)
                //判断三角形内是否有点
                if (out[u][i]+out[i][j]+out[j][u]==m) {
                    //更新a[j]的值,取最大值
                    tmp=area(vertex[u],vertex[i],vertex[j]);
                    if (tmp>a[j]) a[j]=tmp;
                    if (online[u][i]==0) {
                        tmp+=a[i];
                        if (tmp>a[j]) a[j]=tmp;
                    }
                }
        for (j=u+2;j<=n;j++)
            if (a[j]>max) max=a[j];
    }
    if (max==0) printf("die\n");
        else printf("%.2f\n",max/2.);
}
 
int main(){
    scanf("%lld",&n);
    long i,j,tm,s1=0,s2;
    for (i=1;i<=n;i++)
        scanf("%lld%lld",&vertex[i].x,&vertex[i].y);
    //求总面积
    for (i=2;i<n;i++)
        s1+=area(vertex[1],vertex[i],vertex[i+1]);
    scanf("%lld",&tm);
    for (i=1;i<=tm;i++){
        scanf("%lld%lld",&insd[0].x,&insd[0].y);
        s2=0;
        for (j=1;j<=n;j++)
            s2+=area(insd[0],vertex[j],vertex[j%n+1]);
        //利用面积判断点是否在多边形内部
        if (s1==s2) insd[++m]=insd[0];
    }
    prepare();
    dp();
    return 0;
}

T2 不老的传说

题意

20190809194617.png
20190809194626.png

类似于涂色问题,环形问题不多说,断环加倍即可,限制条件if判断就行。终于ac了一道题。。

解析

20190809194742.png
20190809194845.png

代码

#include<bits/stdc++.h>
using namespace std;
int n,c,p,a[410];
int f[410][410],ans=1<<30;
int main(){
    scanf("%d %d %d",&n,&c,&p);
    for(int i=1;i<=n;++i){
        scanf("%d",&a[i]);
        a[i+n]=a[i];
    }
    memset(f,0x3f,sizeof(f));
    for(int i=1;i<=n;++i){
        f[i][i]=f[i+n][i+n]=1;
    }
    for(int l=2;l<=n;++l){
        for(int i=1;i<=2*n-l+1;++i){
            int j=i+l-1;
            if(a[i]==a[j]&&l<=p) f[i][j]=min(f[i+1][j],f[i][j-1]);
            else {
                for(int k=i;k<j;++k){
                    f[i][j]=min(f[i][j],f[i][k]+f[k+1][j]);
                }
            }
        }
    }
    for(int i=1;i<=n;++i){
        if(f[i][i+n-1]){
            ans=min(ans,f[i][i+n-1]);
        }
    }
    printf("%d",ans);
    return 0;
}
/*
5 2 3
1 2 1 2 1
*/

T3 数字游戏

题意

20190809194924.png

话说考场dfs骗了30分,一开始想的距离正解差一点啊,贪心加dp就可以过的水题,真正太蒻了

解析

20190809195048.png

代码

#include<bits/stdc++.h>
using namespace std;
struct node{
    int x;
    int y;
}a[210];
int m,n,k;
int f[210][210];
bool book[210];
long long ans;
bool cmp(node a,node b){
    return a.y>b.y;
}
int main(){
    scanf("%d %d",&n,&m);
    for(int i=1;i<=n;++i){
        scanf("%d",&a[i].x);
    }
    for(int i=1;i<=n;++i){
        scanf("%d",&a[i].y);
    }
    sort(a+1,a+1+n,cmp);
    f[0][0]=0;
    for(int i=1;i<=n;++i){
        for(int j=1;j<=m;++j){
            f[i][j]=max(f[i-1][j],f[i-1][j-1]+a[i].x-a[i].y*(j-1));
        }
    }
    printf("%lld",f[n][m]);
    return 0;
}

T4 多米诺骨牌问题

题意

20190809195145.png

类似于就是背包,考场竟然没想到,打了个爆搜骗了25。

解析

20190809195251.png

代码

跟解析有点不一样v[i]价值,w[i]重量,s背包容积,背包转移即可。

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e4+5; 
int n,s,x,y,tot,ans;
int v[maxn],w[maxn],dp[maxn];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        scanf("%d %d",&x,&y);
        if(x>y){
            s+=x-y;
            v[i]=2*(x-y);
            w[i]=1;
        }
        else{
            s+=y-x;
            v[i]=2*(y-x);
            w[i]=-1;
            tot++;
        }
    }
    for(int i=1;i<=s;++i) dp[i]=maxn;
    dp[0]=0;
    for(int i=1;i<=n;++i){
        for(int j=s;j>=v[i];--j){
            if(dp[j-v[i]]!=maxn){
                dp[j]=min(dp[j],dp[j-v[i]]+w[i]);
            }
        }
    }
    for(int i=s;i>=0;--i){
        if(dp[i]!=maxn){
            ans=dp[i];
            break;
        }
    }
    printf("%d",ans+tot);
    return 0;
}
/*
4
6 1
1 5
1 3
1 2
*/

T5 下楼问题

题意

20190809195405.png
大概就是每一楼有3个门问走到第一楼的最长时间

一道比较简单的dp题,考场看到是英文题便放弃了

20190809195518.png

代码(以后再说吧)

T6 瞬移

题意

20190809195604.png
20190809195622.png

同上

解析

20190809195655.png
20190809195718.png

代码(std)

#include <stdio.h>
#include <stdlib.h>
#include <map>

const int maxn = 1000;
const int maxm = 12;

typedef std::map<std::pair<int, int>, int>::iterator Iter;
std::map<std::pair<int, int>, int> ans[maxn];
int tc, tt, n, m, ma, mi, x, y, bans;
char a[maxn][maxm];

int main ()
{
    freopen("teleportation.in", "r", stdin);
    freopen("teleportation.out", "w", stdout);
  scanf ("%d", &tc);
  for (int tt = 0; tt < tc; tt++)
  {
    scanf ("%d%d%d%d%d%d", &n, &m, &mi, &ma, &x, &y);
    for (int i = 0; i < n; i++)
    {
      scanf ("%s", a[i]);
      // printf ("%s\n", a[i]);
    }
    ans[0].clear ();
    std::pair<int, int> p = std::make_pair<int, int> (x, y);
    ans[0][p] = 0;
    for (int i = 1; i < n; i++)
    {
      ans[i].clear ();
      for (int j = 0; j < m; j++)
      {
        if (a[i][j] == '*')
        {
          for (int k = j + mi; k <= j + ma && k < m; k++)
          {
            //printf ("--%d: [%d, %d]\n", i, j, k);
            if (a[i][k] == '*')
            {
              p = std::make_pair<int, int> (j, k);
              for (Iter it = ans[i - 1].begin (); it != ans[i - 1].end (); ++it)
              {
                int c = it->second + abs (it->first.first - j) + abs (it->first.second - k);
                if (ans[i].find (p) == ans[i].end () || ans[i][p] > c)
                  ans[i][p] = c;
              }
              // printf ("%d: [%d, %d]:%d\n", i, j, k, ans[i][p]);
            }
          }
        }
      }
    }
    bans = -1;
    for (Iter it = ans[n - 1].begin (); it != ans[n - 1].end (); ++it)
    {
      if (bans == -1 || it->second < bans)
      {
        // printf ("[%d, %d]:%d\n", it->first.first, it->first.second, it->second);
        bans = it->second;
      }
    }
    printf ("%d\n", bans);
  }
  return bans >= 0;
}

T7 护士工作安排问题

题意

20190809195812.png
20190809195821.png

一道比较好想不好写的题目

解析

20190809195835.png

代码(std)

#include<stdio.h>
#include<string.h>

const int N = 20;
const int DAY = 5;
const int PAT = 1 << DAY;

int n;
int love[N][PAT];
int req[DAY];
int memo[N][N/2+1][N/2+1][N/2+1][N/2+1][N/2+1];
int bit[PAT][DAY];
int changed[DAY];

void preprocess() {
  for (int i = 0; i < PAT; i++) {
    int k = i;
    for (int j = 0; j < DAY; j++) {
      bit[i][DAY - 1 - j] = k & 1;
      k >>= 1;
    }
  }
}
inline int getDec(int r0, int r1, int r2, int r3, int r4) {
  return (((((((r0 << 1) | r1) << 1) | r2) << 1) | r3) << 1) | r4;
}
void input() {
  scanf("%d", &n);
  for (int i = 0; i < n; i++) {
    for (int j = 0; j < PAT; j++) {
      scanf("%d", &love[i][j]);
    }
  }
  for (int i = 0; i < DAY; i++) {
    scanf("%d", &req[i]);
  }
}
int dp(int p, int r0, int r1, int r2, int r3, int r4) {
  if (memo[p][r0][r1][r2][r3][r4] != -1) return memo[p][r0][r1][r2][r3][r4];
  if (p == 0) {
    return memo[p][r0][r1][r2][r3][r4] = love[0][getDec(changed[0] ^ r0,
        changed[1] ^ r1, changed[2] ^ r2, changed[3] ^ r3, changed[4] ^ r4)];
  }
  int ret = 0;
  for (int i = 0; i < PAT; i++) {
    int rr0 = r0 - (bit[i][0] ^ changed[0]);
    int rr1 = r1 - (bit[i][1] ^ changed[1]);
    int rr2 = r2 - (bit[i][2] ^ changed[2]);
    int rr3 = r3 - (bit[i][3] ^ changed[3]);
    int rr4 = r4 - (bit[i][4] ^ changed[4]);
    if (rr0 >= 0 && rr0 <= p && rr1 >= 0 && rr1 <= p
        && rr2 >= 0 && rr2 <= p && rr3 >= 0 && rr3 <= p
        && rr4 >= 0 && rr4 <= p) {
      int t = dp(p - 1, rr0, rr1, rr2, rr3, rr4) + love[p][i];
      if (t > ret) ret = t;
    }
  }
  return memo[p][r0][r1][r2][r3][r4] = ret;
}
void solve() {
  for (int i = 0; i < DAY; i++) {
    if (req[i] + req[i] > n) {
      req[i] = n - req[i];
      changed[i] = 1;
    } else {
      changed[i] = 0;
    }
  }
  memset(memo, -1, sizeof(memo));
  printf("%d\n", dp(n - 1, req[0], req[1], req[2], req[3], req[4]));
}
int main() {
  freopen("nurse.in", "r", stdin);
  freopen("nurse.out", "w", stdout);
  preprocess();
  int T;
  scanf("%d", &T);
  while (T--) {
    input();
    solve();
  }
  //while (1);
  return 0;
}

T8 循环小数

题意

20190809200027.png
20190809200035.png

给出循环节求分数表达,一道小学数学问题,考场不会写。。

解析

A=b+a(10^m-1)

B=10^(n+m)-10^n

再约分输出A,B即可。

证明自行百度

代码()

转载于:https://www.cnblogs.com/donkey2603089141/p/11414975.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值