「NOI2013」小 Q 的修炼

第一次完整的做出一个提答,花了半个晚上+一个上午+半个下午

总体来说太慢了

对于此题,我认为的难点是观察数据并猜测性质和读入操作

我隔一会就思考这个sb字符串读起来怎么这么麻烦啊


首先可以发现,这个所有的选择都之后往后走,就是个topo图

  • task1,2,3

    观察到数据有形如

    s x x+11
    v 3 + c y
    v 4 + c y
    v 5 + c y
    v 6 + c y
    v 7 + c y
    v 8 + c y
    v 9 + c y
    v 10 + c y
    v 11 + c y
    v 12 + c y

    之类的东西,而且每个这样的循环后面有一个这样的东西

    i v 3 c 0 43 45
    v 1 - v 3
    i c 0 c 1 46 0
    v 1 + v 3
    v 3 - v 3
    i v 4 c 0 48 50
    v 1 - v 4
    i c 0 c 1 51 0
    v 1 + v 4
    v 4 - v 4
    ...

    发现这个就是把正的数据加到1上,负的不变并清空

    这样就没法贪心或者dp了

    然后我们又发现循环长度很小,直接爆搜就行了

    代码搞丢了..

    S_1 要讨论走哪个循环

    S_2 直接爆搜

    S_3 发现又很多组,分组爆搜

  • task4,5,6

    最开始对变量2有一个正的初值

    然后

    s 5 8
    v 2 - c 10
    v 1 + c 22750
    i c 0 c 1 8 0
    i v 2 c 9 9 10
    i c 0 c 1 14 0

    循环节长这样

    每次如果选择,会有一些跳转之类的

    发现2的初值比较小而且后面只会减

    考虑dp

    \(dp_{i,j}\)第\(i\)行第\(2\)个变量的值是\(j\)的时候最大的\(1\)

    然后模拟转移,记录路径就可以了

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define ll long long
    using std::max;
    const int N=6010;
    int n,m;
    char op[5],t0[10],t1[10];
    int x0,x1,x2,x2;
    struct koito_yuu
    {
    int op,a,b,c;
    koito_yuu(){}
    koito_yuu(int Op,int A,int B,int C){op=Op,a=A,b=B,c=C;}
    }yuu[N];
    struct node
    {
    int i,j,cho;
    node(){}
    node(int I,int J,int Cho){i=I,j=J,cho=Cho;}
    }pre[N][5010];
    ll dp[N][5010];
    int main()
    {
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
    scanf("%s",op);
    if(op[0]=='s')
    {
    tim[++k]=i;
    scanf("%d%d",&x1,&x2);
    yuu[i]=koito_yuu(1,x1,x2,0);
    }
    else if(op[0]=='v')
    {
    scanf("%d%s%s%d",&x0,t0,t1,&x1);
    yuu[i]=koito_yuu(2,x0,t1[0]=='+'?x1:-x1,0);
    }
    else
    {
    scanf("%s%d%s%d%d%d",t0,&x0,t1,&x1,&x2,&x3);
    if(t0[0]=='c'&&t1[0]=='c') yuu[i]=koito_yuu(3,x2,0,0);
    else if(t0[0]=='v'&&t1[0]=='c') yuu[i]=koito_yuu(4,x1,x2,x3);
    }
    }
    memset(dp,-0x3f,sizeof dp);
    int inf=dp[0][0];
    dp[0][0]=0;
    for(int i=1;i<=n;i++)
    for(int j=0;j<=5000;j++)
    if(dp[i-1][j]!=inf)
    {
    if(yuu[i].op==1)
    {
    int a=yuu[i].a,b=yuu[i].b;
    if(dp[a][j]<dp[i][j])
    {
    pre[a][j]=node(i,j,1);
    dp[a][j]=dp[i][j];
    }
    if(dp[b][j]<dp[i][j])
    {
    pre[b][j]=node(i,j,2);
    dp[b][j]=dp[i][j];
    }
    }
    else if(yuu[i].op==2)
    {
    int a=yuu[i].a,b=yuu[i].b;
    if(a==1)
    {
    if(dp[i+1][j]<dp[i][j]+b)
    {
    pre[i+1][j]=node(i,j,0);
    dp[i+1][j]=dp[i][j]+b;
    }
    }
    else
    {
    int t=max(0,j+b);
    if(dp[i+1][t]<dp[i][j])
    {
    pre[i+1][t]=node(i,j,0);
    dp[i+1][t]=dp[i][j];
    }
    }
    }
    else if(yuu[i].op==3)
    {
    int a=yuu[i].a;
    if(dp[a][j]<dp[i][j])
    {
    pre[a][j]=node(i,j,0);
    dp[a][j]=dp[i][j];
    }
    }
    else
    {
    int a=yuu[i].a,b=yuu[i].b,c=yuu[i].c;
    if(j<a)
    {
    if(dp[b][j]<dp[i][j])
    {
    pre[b][j]=node(i,j,0);
    dp[b][j]=dp[i][j];
    }
    }
    else
    {
    if(dp[c][j]<dp[i][j])
    {
    pre[c][j]=node(i,j,0);
    dp[c][j]=dp[i][j];
    }
    }
    }
    }
    int tj=0;
    for(int i=1;i<=5000;i++)
    if(dp[n+1][tj]<dp[n+1][i])
    tj=i;
    int ti=n+1,cnt=0;
    while(ti)
    {
    int tx=ti,ty=tj;
    ti=pre[tx][ty].i,tj=pre[tx][ty].j;
    if(pre[tx][ty].cho) ans[++cnt]=pre[tx][ty].cho;
    }
    for(int i=cnt;i;i--) printf("%d\n",ans[i]);
    return 0;
    }

    4,5,6都是一样的

    我本地跑6的时候居然开不下空间,还压了一会T_T

  • task7,8,9,10

    这四个点就是前面的结合

    最开始的时候有2控制跳转的东西

    中间就是1,2,3点的循环

    差不多175行一个周期

    对周期压变量2的长度dp,每个周期里面爆搜

    说起来简单,写起来还是很麻烦的

    我这个代码要把in的最后几行删掉

    Code:

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define ll long long
    using std::max;
    using std::min;
    const int N=35010;
    int n,m;
    char op[5],t0[10],t1[10];
    int x0,x1,x2,x3;
    struct koito_yuu
    {
    int op,a,b,c;
    koito_yuu(){}
    koito_yuu(int Op,int A,int B,int C){op=Op,a=A,b=B,c=C;}
    }yuu[N];
    struct node
    {
    int i,j,cho;
    node(){}
    node(int I,int J,int Cho){i=I,j=J,cho=Cho;}
    }pre[N][1010];
    ll dp[N][1010];
    int Id[N],as[N][20],yuy[20][20],ct[N];
    ll solve(int id,int L,int R)
    {
    int n=0;
    for(int i=L;i<=R;i++)
    {
    if(yuu[i].op==1) ++n,yuy[n][0]=0;
    if(yuu[i].op==2) yuy[n][++yuy[n][0]]=yuu[i].b;
    if(yuu[i].op==3) break;
    }
    ll mx=-(1ll<<52);
    ct[id]=n;
    for(int s=0;s<1<<n;s++)
    {
    ll sum[20]={};
    for(int i=1;i<=n;i++)
    if(s>>i-1&1)
    {
    for(int j=1;j<=10;j++)
    sum[j]+=yuy[i][j];
    }
    ll su=0;
    for(int i=1;i<=10;i++) su+=sum[i]>0?sum[i]:-sum[i];
    if(mx<su)
    {
    mx=su;
    for(int i=1;i<=n;i++)
    if(s>>i-1&1)
    as[id][i]=1;
    else
    as[id][i]=2;
    }
    }
    return mx;
    }
    int endro[N],k,ans[N];
    int main()
    {
    freopen("train8.in","r",stdin);
    freopen("train8.out","w",stdout);
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
    scanf("%s",op);
    if(op[0]=='s')
    {
    scanf("%d%d",&x1,&x2);
    x2=min(x2,n+1);
    yuu[i]=koito_yuu(1,x1,x2,0);
    }
    else if(op[0]=='v')
    {
    scanf("%d%s%s%d",&x0,t0,t1,&x1);
    if(t1[0]=='c')
    {
    yuu[i]=koito_yuu(2,x0,t0[0]=='+'?x1:-x1,0);
    }
    else
    {
    yuu[i]=koito_yuu(3,x0,0,x1);
    if(x0==12) endro[++k]=i;
    }
    }
    else
    {
    scanf("%s%d%s%d%d%d",t0,&x0,t1,&x1,&x2,&x3);
    x2=min(x2,n+1),x3=min(x3,n+1);
    if(t0[0]=='c'&&t1[0]=='c') yuu[i]=koito_yuu(4,x2,0,0);
    else if(t0[0]=='v'&&t1[0]=='c') yuu[i]=koito_yuu(5,x1,x2,x3);
    }
    }
    memset(dp,-0x3f,sizeof dp);
    dp[1][0]=0;
    for(int i=1;i<=k;i++)
    {
    int tp;
    for(int j=endro[i-1]+1;;j++)
    if(yuu[j].op==1&&yuu[j].b-yuu[j].a==11)
    {
    tp=j-1;
    break;
    }
    ll ad=solve(i,tp+1,endro[i]);
    for(int l=endro[i-1]+1;l<=tp;l++)
    for(int j=0;j<=1000;j++)
    {
    if(yuu[l].op==1)
    {
    int a=yuu[l].a,b=yuu[l].b;
    if(dp[a][j]<dp[l][j])
    {
    dp[a][j]=dp[l][j];
    pre[a][j]=node(l,j,1);
    }
    if(dp[b][j]<dp[l][j])
    {
    dp[b][j]=dp[l][j];
    pre[b][j]=node(l,j,2);
    }
    }
    else if(yuu[l].op==2)
    {
    int b=yuu[l].b;
    int t=max(0,j+b);
    if(dp[l+1][t]<dp[l][j])
    {
    dp[l+1][t]=dp[l][j];
    pre[l+1][t]=node(l,j,0);
    }
    }
    else if(yuu[l].op==4)
    {
    int a=yuu[l].a;
    if(dp[a][j]<dp[l][j])
    {
    dp[a][j]=dp[l][j];
    pre[a][j]=node(l,j,0);
    }
    }
    else
    {
    int a=yuu[l].a,b=yuu[l].b,c=yuu[l].c;
    if(j<a)
    {
    if(dp[b][j]<dp[l][j])
    {
    dp[b][j]=dp[l][j];
    pre[b][j]=node(l,j,0);
    }
    }
    else
    {
    if(dp[c][j]<dp[l][j])
    {
    dp[c][j]=dp[l][j];
    pre[c][j]=node(l,j,0);
    }
    }
    }
    }
    int s=tp+1,t=endro[i]+1;
    Id[s]=i;
    for(int j=0;j<=1000;j++)
    if(dp[t][j]<dp[s][j]+ad)
    {
    dp[t][j]=dp[s][j]+ad;
    pre[t][j]=node(s,j,3);
    }
    }
    //9.22925584
    //10.20218188
    int tj=0;
    for(int i=1;i<=1000;i++)
    if(dp[n+1][tj]<dp[n+1][i])
    tj=i;
    int ti=n+1,cnt=0;
    while(ti)
    {
    int tx=ti,ty=tj;
    ti=pre[tx][ty].i,tj=pre[tx][ty].j;
    if(pre[tx][ty].cho)
    {
    if(pre[tx][ty].cho==3)
    {
    int id=Id[ti];
    for(int i=ct[id];i;i--) ans[++cnt]=as[id][i];
    }
    else
    ans[++cnt]=pre[tx][ty].cho;
    }
    }
    for(int i=cnt;i;i--) printf("%d\n",ans[i]);
    return 0;
    }

2019.4.12

「NOI2013」小 Q 的修炼 解题报告的更多相关文章

  1. 「SCOI2015」小凸想跑步 解题报告

    「SCOI2015」小凸想跑步 最开始以为和多边形的重心有关,后来发现多边形的重心没啥好玩的性质 实际上你把面积小于的不等式列出来,发现是一次的,那么就可以半平面交了 Code: #include & ...

  2. 「SCOI2015」小凸解密码 解题报告

    「SCOI2015」小凸解密码 题意:给一个环,定义一段连续的极长\(0\)串为\(0\)区间,定义一个位置的离一个\(0\)区间的距离为这个位置离这个区间中\(0\)的距离的最小值,每次询问一个位置 ...

  3. 「SCOI2015」小凸玩矩阵 解题报告

    「SCOI2015」小凸玩矩阵 我好沙茶啊 把点当边连接行和列,在外面二分答案跑图的匹配就行了 我最开始二分方向搞反了,样例没过. 脑袋一抽,这绝壁要费用流,连忙打了个KM 然后wa了,一想这个不是完 ...

  4. 「SCOI2015」小凸玩密室 解题报告

    「SCOI2015」小凸玩密室 虽然有心里在想一些奇奇怪怪的事情的原因,不过还是写太久了.. 不过这个题本身也挺厉害的 注意第一个被点亮的是任意选的,我最开始压根没注意到 \(dp_{i,j}\)代表 ...

  5. 【LOJ】#3020. 「CQOI2017」小 Q 的表格

    #3020. 「CQOI2017」小 Q 的表格 这个的话求出来\(g = gcd(a,b)\) 会修改所有gcd为g的位置 我们要求\((g,g)\)这个位置的数一定是\(g^{2}\)的倍数 之后 ...

  6. 「SCOI2014」方伯伯运椰子 解题报告

    「SCOI2014」方伯伯运椰子 可以看出是分数规划 然后我们可以看出其实只需要改变1的流量就可以了,因为每次改变要保证流量守恒,必须流成一个环,在正负性确定的情况下,变几次是无所谓的. 然后按照套路 ...

  7. 「SDOI2017」树点涂色 解题报告

    「SDOI2017」树点涂色 我sb的不行了 其实一开始有一个类似动态dp的想法 每个点维护到lct树上到最浅点的颜色段数,然后维护一个\(mx_{0,1}\)也就是是否用虚儿子的最大颜色 用个set ...

  8. 「SCOI2014」方伯伯的 OJ 解题报告

    「SCOI2014」方伯伯的 OJ 和列队有点像,平衡树点分裂维护即可 但是需要额外用个set之类的对编号查找点的位置 插入完了后记得splay,删除时注意特判好多东西 Code: #include ...

  9. 洛谷 P3698 [CQOI2017]小Q的棋盘 解题报告

    P3698 [CQOI2017]小Q的棋盘 题目描述 小 Q 正在设计一种棋类游戏. 在小 Q 设计的游戏中,棋子可以放在棋盘上的格点中.某些格点之间有连线,棋子只能在有连线的格点之间移动.整个棋盘上 ...

随机推荐

  1. GTX 750TI 使用 ffmpeg 时无法用 GPU HEVC(h.265) 进行加速

    官网版本好像不是能加速的,所以在github上找到一个已经带gpu加速的. https://github.com/illuspas/ffmpeg-hw-win32 GPU加速命令格式: ffmpeg. ...

  2. 并发concurrent---1

    背景:并发知识是一个程序员段位升级的体现,同样也是进入BAT的必经之路,有必要把并发知识重新梳理一遍. 并发concurrent: 说到并发concurrent,肯定首先想到了线程,创建线程有两种方法 ...

  3. Java 适配器(Adapter)模式

    一.什么是适配器模式: 把一个接口变成另外一个接口,使得原本因接口不匹配无法一起工作的两个类一起工作. 二.适配器模式的分类和结构: 适配器模式有类的适配器模式和对象的适配器模式两种. 1.类的适配器 ...

  4. 关于视频断点续播和H5的本地存储

    前段时间,需要在下实现一个视频的断点续播功能,呃,我不会呀,这就很尴尬了.然后呢,在下就想起了一个叫做localStorage的东西.这是个什么东西呢?在网上查阅了一些资料后,在下发现这是webSto ...

  5. Spring注解IOC/DI(4)

    2019-03-08/11:10:17 演示:使用注解的方式完成注入对象中的效果 注解参考链接:https://www.cnblogs.com/szlbm/p/5512931.html Spring中 ...

  6. Cookie 数据浅谈

    Cookie 是一些数据, 存储于你电脑上的文本文件中. 当 web 服务器向浏览器发送 web 页面时,在连接关闭后,服务端不会记录用户的信息.   Cookie 的作用就是用于解决 "如 ...

  7. Jinja2用法总结

    Jinja2用法总结   一:渲染模版 要渲染一个模板,通过render_template方法即可. @app.route('/about/') def about(): # return rende ...

  8. ButterKnife的使用详解

    ButterKnife的使用详解 1,概述: ButterKnife则是注解中相对简单易懂的很不错的开源框架. ButterKnife是目前常用的一种依托Java注解机制实现辅助代码生成的框架:用到了 ...

  9. 工具资源系列之给虚拟机装个centos

    前文我们已经讲解了如何在 mac 系统上安装虚拟机软件,这节我们接着讲解如何利用虚拟机安装 centos 镜像. 安装镜像的大致步骤基本相同,只不过是配置项略显不同而已,如果需要安装其他系统镜像,请参 ...

  10. python-重载

    重载概念 重载是对继承的父类方法进行重新定义.重载可以重新定义方法还可以重新定义运算符.因为通过继承的类不一定能满足当前类的需求.在当前类中只需要修改部分内容而达到自己的需求. 重载特点 减少代码量和 ...