首页 > 其他分享 >20230311模拟赛(jnxxhzz)

20230311模拟赛(jnxxhzz)

时间:2023-04-08 23:24:47浏览次数:33  
标签:rt 20230311 int 团建 括号 maxn 模拟 jnxxhzz dp

T1.团建游戏I

dp,略

 

T2.团建游戏II

每一次加括号->把一些运算去反

在+后加括号是没有用的,所以每一次只用在-后加

考虑重叠的括号:最多是两层,第三层相当于一层了

对于每一个位置,我们可以用dp记录从这个数字的后面一位往前看有多少个单独的"("

也就是说,对于数字16,我们从"||"向前看:   3 - ( 5 + 5 - 16 )  ||  + 3

这样就可以写出转移的式子了

dp_{i,j}​编辑表示第i个数字时,前面有多少个没有")"的"("时,前i个的值,j=0/1/2

1* i前面是"-",那么i可以自己加括号,而在自己加括号是,仍然是-a[i]

dp_{i,0}=\left\{\begin{matrix} dp_{i-1,1}+a_i \\ dp_{i-1,0}-a_i \\ dp_{i-1,2}-a_i\end{matrix}\right.

dp_{i,1}=\left\{\begin{matrix} dp_{i-1,1}+a_i \\ dp_{i-1,0}-a_i \\ dp_{i-1,2}-a_i \end{matrix}\right.

dp_{i,2}=\left\{\begin{matrix} dp_{i-1,1}+a_i\\ dp_{i-1,2}-a_i\\ \end{matrix}\right.

2* i前面是"+"

dp_{i,0}=\left\{\begin{matrix} dp_{i-1,0}+a_i\\dp_{i-1,1}-a_i \\ dp_{i-1,2}+a_i \end{matrix}\right.

dp_{i,1}=\left\{\begin{matrix} dp_{i-1,1}-a_i \\ dp_{i-1,2}+a_i \end{matrix}\right.

dp_{i,2}=dp_{i-1,2}+a_i

最后的答案就是\max(dp_{n,j})

考虑初始化:\left\{\begin{matrix} dp_{0,0}=0 \\ dp_{0,1}=-\infty \\ dp_{0,2}=-\infty \end{matrix}\right.

防止dp[0][1]和dp[0][2]被用

代码

#include <bits/stdc++.h>
using namespace std;
#define ll long long

const int maxn=1e5+10;
int n,T;
ll a[maxn],f[maxn],dp[maxn][3],ans=0;
char ch;

int main(){
  scanf("%d",&T);
  while(T--){
      scanf("%d",&n);
      scanf("%lld",&a[1]);
      for(int i=2;i<=n;i++){
        ch=getchar();ch=getchar();
      if(ch=='-') f[i]=-1;
      else f[i]=1;
      ch=getchar();
      scanf("%lld",&a[i]);    
    }
    f[1]=1;
    dp[0][1]=dp[0][2]=-1e18;//不用memset,会超时!!!
    for(int i=1;i<=n;i++){
      if(f[i]==1){
          dp[i][0]=max(dp[i-1][0]+a[i],max(dp[i-1][1]-a[i],dp[i-1][2]-a[i]));
          dp[i][1]=max(dp[i-1][1]-a[i],dp[i-1][2]+a[i]);
          dp[i][2]=dp[i-1][2]+a[i];
      }
      else{
          dp[i][0]=max(dp[i-1][0]-a[i],max(dp[i-1][1]+a[i],dp[i-1][2]-a[i]));
          dp[i][1]=max(dp[i-1][0]-a[i],max(dp[i-1][1]+a[i],dp[i-1][2]-a[i]));
          dp[i][2]=max(dp[i-1][1]+a[i],dp[i-1][2]-a[i]);
      }
    }
    ans=max(dp[n][0],max(dp[n][1],dp[n][2]));
    printf("%lld\n",ans);
  }
  return 0;
}

 

T3.团建游戏III

分析发现:

1.在最短距离中,不可能走回头路,所以左右移动距离未|tx|

2.不遇到障碍物不转弯,贴着边缘走路径最短

所以对于每一个障碍物,我们只需要知道它的上、下、左边界

先按照横坐标排序

可以朴素地建图,再跑最短路(考场做法),但只有80分,会TLE

对于每一个走出来的点,它只有可能在遇到障碍时往上或往下

又可以用dp来解决,dp[i][0]表示第i个障碍走上面的距离,dp[i][1]表示走下面

再用线段树维护,找到这个点从哪里来即可

也可以用set暴力,用扫描线的思想完成

代码

#include <bits/stdc++.h>
using namespace std;
#define mid (l+r)/2
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define lb(x) lower_bound(b+1,b+len+1,x)-b
#define int long long

const int maxn=1e6+10;
int n,tx,tr[maxn*4],dp[maxn][2],b[maxn*2],m,t;
struct node{
  int a,b,c,d;
  bool operator < (const node &rhs) const{
    return a<rhs.a;
  }
}a[maxn];

void add(int l,int r,int rt,int lx,int rx,int x){
  if(lx<=l&&rx>=r){tr[rt]=x;return;}
  if(lx<=mid) add(lson,lx,rx,x);
  if(rx>mid) add(rson,lx,rx,x);
}

void query(int l,int r,int rt,int x){
  t=max(t,tr[rt]);
  if(l==r) return ;
  if(x<=mid) query(lson,x);
  else query(rson,x); 
}

int read(){
  int x=0,f=1;char ch=getchar();
  while(!isdigit(ch)){if(ch=='-') f=-1;ch=getchar();}
  while(isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
  return x*f;
}

signed main(){
  n=read();tx=read();
  for(int i=1;i<=n;i++){
      a[i].a=read();a[i].b=read();a[i].c=read();a[i].d=read();
      if(a[i].a>a[i].c) swap(a[i].a,a[i].c);
      if(a[i].b>a[i].d) swap(a[i].b,a[i].d);
      b[i]=a[i].b,b[i+n]=a[i].d;
  }
  m=n*2+1;b[m]=0;
  sort(b+1,b+m+1);
  a[++n]=(node){tx,0,tx,0};
  sort(a+1,a+n+1);
  int len=unique(b+1,b+m+1)-b-1;
  for(int i=1;i<=n;i++){
      t=0;query(1,n,1,lb(a[i].b));
      dp[i][0]=min(dp[t][0]+abs(a[t].b-a[i].b),dp[t][1]+abs(a[t].d-a[i].b));
      t=0;query(1,n,1,lb(a[i].d));
      dp[i][1]=min(dp[t][1]+abs(a[t].d-a[i].d),dp[t][0]+abs(a[t].b-a[i].d));
      add(1,n,1,lb(a[i].b),lb(a[i].d),i);
  }
  printf("%lld\n",dp[n][0]+tx);
  return 0;
}

总结

1.涉及到从前面一个状态转移的都可以考虑用dp,如T3中的dp

2.dp的推导过程中,明确表示内容,如T2中记录的是第i个数字的括号数

标签:rt,20230311,int,团建,括号,maxn,模拟,jnxxhzz,dp
From: https://www.cnblogs.com/hewanying0622/p/17299544.html

相关文章

  • 20230318模拟赛(jnxxhzz)
    T1.彩虹树对于每一个u,v,我们都要去算u->v路径上有多少个不同的元素很显然,<spanclass="cke_resetcke_widget_drag_handler_container"><imgsrc="data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw=="width="15"height=......
  • 20230225模拟赛(jnxxhzz)
    A.bubble冒泡排序考虑k次冒泡中的每一次,会把最大的数移到最右边而只有最大数在变吗?以14352为例5的右边相对顺序是不变的,而5的左边是要变的发现在不断地把小的往前面移,且每一个较小的数都会往前最多移动k个但我们不好算每个i往前移k个的数考虑反向处理:算有哪些点可以被......
  • 1223. 掷骰子模拟
    题目链接:1223.掷骰子模拟方法:回溯+记忆化搜索解题思路回溯要点参数列表根据题目中的操作确定在递归中需要用到的上一层的某个变量或性质。递归边界即递归的最底层,确定其返回值。记忆化搜索由于在递归中会重复计算某一状态的值,那么我们在第一次计算出来后将其保存......
  • 基于matlab模拟雷达信号检测中的恒虚警处理方法(慢门限和快门限)
    ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。......
  • 基于Matlab模拟圆周阵列天线
    ✅作者简介:热爱科研的Matlab仿真开发者,修心和技术同步精进,matlab项目合作可私信。......
  • 数组模拟环形队列的思路及代码
    JAVA实现数组模拟环形队列的思路及代码前言在对Java实现数组模拟队列零了解的情况下,建议先去阅读《JAVA实现数组模拟单向队列的思路及代码》一文,可以辅助理解本文核心思想。一、环形数组队列实现:让数组达到复用的效果,即:当我们从数组队列中取出了数据,那取出数据后后这个空间可......
  • 数组模拟单向队列的思路及代码
    JAVA实现数组模拟单向队列的思路及代码一、什么是队列?队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头。队列中没有元素时,称......
  • C/C++模拟ATM机存取款管理系统[2023-04-07]
    C/C++模拟ATM机存取款管理系统[2023-04-07]2、模拟ATM机存取款管理系统模拟银行的自动取款机使用过程中的界面和用户交互过程。实现查询银行卡余额、取款修改密码、退出系统等功能。(一)功能要求及说明:(1)将银行账户的卡号,户名,密码和账户余额从外部文件(银行账户.txt)中读入......
  • 模拟循环批量请求后台接口
    使用async,await处理异步请求。用Promise,setTimeout函数模拟后台接口<!DOCTYPEhtml><html><scripttype="text/javascript">vararr=[];varbatchSize=10;for(i=0;i<30;i++){arr.push(i);}functionb(startIdx,endIdx){ returnnewPromise((res......
  • 邮箱密码-2020模拟
    【题目描述】小明的电子邮箱密码忘记了。请你帮他找出密码。他零星记得密码的信息如下:1)密码是六位数字,前面两位是31;2)最后两位数字相同;3)能被16和46整除;请你找出所有可能的密码并统计个数。【评分标准】30分︰正确打印出一组符合的六位数(程序不报错);80分∶在满足30基础......