首页 > 其他分享 >7.26 Dp 主题赛 赛后总结

7.26 Dp 主题赛 赛后总结

时间:2024-07-27 14:55:50浏览次数:5  
标签:ch zyc Yc 7.26 dp pos minv 赛后 Dp

T1

T1看上去就很板,开场后有几个人一直在说话导致我心烦意乱,加上 Sorato 和 Psm 很快就切掉,可我确一直没有思路,所以开始的时候很慌。后来冷静下来仔细思考一下,首先注意到数据范围允许\(O(n^2)\)的dp,不难想到设置一个这样的dp状态,\(f[i]\)表示将区间\([1,i]\)变成美丽的所需的最小花费,那么有一个很显然的dp转移方程:\(f[i]=min(f[i],f[j-1]+ask(j,i))\) ,其中\(ask(j,i)\)表示把该区间变成偶回文的所需的花费。考虑 枚举 i,j 需要两重循环,这就要求我们用 \(O(logn)\)甚至是\(O(1)\)的复杂度来得到 \(ask(j,i)\)的值。赛时由于心态问题,考虑到这一步就卡住了,注意到这个值很显然可以 \(O(n^2)\)预处理出来,所以本题得到解决。

这启示我们在遇到某些值不好暴力处理的时候,不妨考虑能否预处理,或者数据结构优化一下?

T2

T2是一道博弈dp,首先码了一个dfs交上去30,调成记忆化之后变成50了,实际上记忆化就是正解,但可能是由于数据问题莫名其妙一直RE,必须开到远大于给定数据范围的值才能通过,赛时最后还是A了,但还是因为一些场外因素耽误了很多时间。

T3

T3有点智慧,赛时码了一个dfs交上去,拿了5分,我看大多数都是30,35,还以为暴搜码炸了,调那个暴搜调到死,最后告诉我,暴搜就是5分。fyx把暴搜换成bfs得了50,所以以后还是码bfs吧。

T3比较智慧的地方在于一步转化:考虑对于当前的字符串s,枚举所有情况,判断是否能在k步之内实现。那么就有两个问题,1.情况总数是多少?答案是一个组合数级别的:\(C_n^a*C_{n-a}^b\),也就是n的阶乘除以a,b,c,阶乘的乘积。第二个问题,如何判断能否实现呢?考虑一个这样的贪心:对于一个字符ch,设它在s中出现的第x次对应的位置为u,在枚举出的串第x次出现的位置为v,那么显然是把u换到v最优。我们把新字符串上的每个位置令赋一个值表示此位置对应在原串的位置,那么答案即为逆序对个数。考虑优化这个算法,既然是dp题,又注意到字符串只有:'K','E','Y'这三个字符,加上本题对于步数的限制,所以设置\(f[i][j][k][t]\)表示当前新串已经使用了\(i+j+k\)个位置,使用了 i个K,j 个E,k 个Y ,且 一共换了 t次,的方案数。显然可以\(O(1)\)转移,于是本题得到解决。

T4

这道题出的很没意思,把暴力加个记忆化就A了,难点在于如何暴力?赛时想码暴力的部分分确实不会。

这个方法应该是可复制的,可以记录一下,把起点,终点,墙,锤子都用一个结构体类型的变量来存储,暴搜时暴力向两边拓展即可。加个记忆化复杂度就来到了\(O(n^2)\),就过了。可以放一下代码:

code

#include<bits/stdc++.h>
// #include<windows.h>
using namespace std;

using Yc = long long;
const Yc zyc = 3010 ;

Yc n,X,inf;
struct Zyc{

    Yc pos,f,i;

    friend bool operator <(Zyc a,Zyc b){
        return a.pos<b.pos;
    }

};
vector<Zyc>a;
Yc flag[zyc];
Yc f[zyc][zyc][2];

inline Yc read(){

    Yc x = 0, f = 1; char ch = getchar();
    while (ch < '0' || ch > '9') { if (ch == '-') f = -1; ch = getchar(); }
    while (ch >= '0' && ch <= '9') { x = x * 10 + ch - '0'; ch = getchar(); }
    return x * f;

}

inline Yc Dfs(Yc l,Yc r,Yc now){

    if(f[l][r][now]!=0x3f3f3f3f3f3f3f3f)  return f[l][r][now];
    Yc minv=inf,pos=(now==0)?a[l].pos:a[r].pos;

    if(r+1<n){
        if(a[r+1].f==1) //终点
            minv=min(minv,a[r+1].pos-pos);
        else  if(a[r+1].f==2&&flag[a[r+1].i])//墙且有锤子
            minv=min(minv,a[r+1].pos-pos+Dfs(l,r+1,1));
        else  if(a[r+1].f==3){//锤子
            flag[a[r+1].i]=1;
            minv=min(minv,a[r+1].pos-pos+Dfs(l,r+1,1));
            flag[a[r+1].i]=0;
        }
    }
    if(l>0){
        if(a[l-1].f==1)//终点
            minv=min(minv,pos-a[l-1].pos);
        else  if(a[l-1].f==2&&flag[a[l-1].i])
            minv=min(minv,pos-a[l-1].pos+Dfs(l-1,r,0));
        else  if(a[l-1].f==3){
            flag[a[l-1].i]=1;
            minv=min(minv,pos-a[l-1].pos+Dfs(l-1,r,0));
            flag[a[l-1].i]=0;
        }
    }

    f[l][r][now]=minv;
    return minv;

}

signed main(){

    freopen("hammer.in","r",stdin);
    freopen("hammer.out","w",stdout);

    memset(f,0x3f,sizeof(f));
    n=read();X=read();inf=LONG_LONG_MAX;

    a.push_back({0,0,0});a.push_back({X,1,0});

    for(Yc i=1;i<=n;i++)
        a.push_back((Zyc){read(),2,i});
    for(Yc i=1;i<=n;i++)
        a.push_back((Zyc){read(),3,i});
    
    sort(a.begin(),a.end());

    n=2*n+2;
    for(Yc i=0;i<n;i++)
        if(a[i].f==0){
            Yc t=Dfs(i,i,0);
            if(t==inf||t<0)  cout<<-1;
            else  cout<<t;
            cout<<'\n';
        }

    // system("pause");

    return 0;

}

代码简洁,思路清晰,通俗易懂,我一遍就码对了,甚至都没有debug。

标签:ch,zyc,Yc,7.26,dp,pos,minv,赛后,Dp
From: https://www.cnblogs.com/yxans/p/18326945/2024_7_26_contest

相关文章

  • dp专题
    1.花店橱窗原题链接:https://ac.nowcoder.com/acm/contest/87275/1005注意放与不放是平行的查看代码#include<bits/stdc++.h>#defineintlonglongusingnamespacestd;intva[110][110];intf[1000000];structnode{inta[110];intt;}way[110][110];//......
  • Diffusion|DDPM 理解、数学、代码
    Diffusion论文:DenoisingDiffusionProbabilisticModels参考博客openinnewwindow;参考paddle版本代码:aistudio实践链接openinnewwindow该文章主要对DDPM论文中的公式进行小白推导,并根据ppdiffuser进行DDPM探索。读者能够对论文中的大部分公式如何得来,用在了什么......
  • ScheduledThreadPoolExecutor
    定时任务ScheduledThreadPoolExecutor类有两个用途:指定时间延迟后执行任务;周期性重复执行任务。JDK1.5之前,主要使用Timer类来完成定时任务,但是Timer有以下缺陷:Timer是单线程模式;如果在执行任务期间某个TimerTask耗时较久,就会影响其它任务的调度;Timer的任务调度是基于......
  • 2024736DP专项练习赛
    前言比赛链接榜上那个冒着蓝光的就是我……提交记录跟答辩一样……\(\color{#F8BBD0}Heldivis%%%%%%%%%%%%%%%%%%%\)吐槽一下,虽然挂着DP专题赛的名字,但除了T1T3以外,全是记搜题(虽然好像只有四道题来着)。T1签到题,\(n\)范围很小,先用区间dp求出任意区间达到最终状态......
  • Luogu P3177 树上染色 [ 蓝 ] [ 树形 dp ] [ 贡献思维 ]
    一道很好的树形dp!!!!!树上染色。错误思路定义\(dp[u][i]\)表示以\(u\)为根的子树中,把\(i\)个点染成黑色的最大收益。但这样写,就在转移的时候必须枚举每一个点,复杂度过大,而且还不好写,是十分错误的写法。正确思路一般看到有关树上“路径”的题,就要把路径拆成一个个独立的......
  • 2024.7.26总结
    今天学习一些基本DP线性DP区间DP状压DP树形DP数位DP不好定转移顺序就用记忆化搜索。线性DP一般定义形如\(dp_{i,s}\)的状态,表示考虑了前\(i\)个,限制为\(s\)的最优解。视情况可以把\(i\)压掉,或者把\(s\)在枚举中体现以此压掉。区间DP是从小区间合并到大区间,注意转移顺序,......
  • DP选讲做题记录 by 付乙淼
    DP选讲P5074EattheTrees最简单的插头DP,轮廓线和插头可以很轻松存储状态和转移。P4719【模板】"动态DP"&动态树分治P5024[NOIP2018提高组]保卫王国动态DP一般就是简单的DP带单点修改,而且给你放到树上,这样你就不得不写树剖,写树剖就需要维护重链,我们就要写出也就是......
  • 7.26每日一练
    1.学生管理系统(增删改查)#include<stdio.h>#include<string.h>intmain(intargc,constchar*argv[]){ intnum=0; inta=0,b=0,c=0; inti,j; intm,n; charadd1[30],add2[30],add3[30]; ints,sub,x,y; charmod[30]; intex; intlen1,len2,len3;......
  • 学习Java的第十一天啦(2024.7.26)
    1.死锁的条件:死锁的产生还涉及到一些具体的条件,这些条件可以被看作是死锁产生的必要条件,包括:1.互斥条件:资源不能被多个进程或线程同时访问,即资源是互斥的。2.请求保持条件:进程或线程在请求资源时,已经持有其他资源,并且不愿意释放已经持有的资源。3.不可剥夺条件:已经分配给进......
  • 7.26课后作业
    课堂笔记整理思维导图二、使用fgets统计给定文件的行号intmain(intargc,constchar*argv[]){ intcount=0; FILE*file=fopen("./text.txt","r"); charbuf[20]=""; char*data=fgets(buf,sizeof(buf),file); while(data!=NULL){ intindex=strlen(data......