zoukankan      html  css  js  c++  java
  • 8.10题解

    T1

    这题竟然真是贪心,我xxxx,考试的时候本来想到贪心了,结果,我在代码上写了句话“//贪心不太对的样子,跳近一点多跳几个格子,可能可以给下一个青蛙留出落脚点”,我当时一定是脑子废掉了想那么多,然后这题我就一点头绪都没有了,在看了大概一个多小时什么都没打之后,我把它弃掉之后,在交卷前最后20多分钟随便打了个DP?结果RE0了

    说说它的贪心吧,对于你每一只青蛙都尽量跳到它可以跳到的最远的地方,毕竟你如果不跳的最远的话,你占的石头就会变多,给后面的青蛙留下的石头就会更少,关于我那个zz的认为贪心不对的想法,我们来想一想,对于每一个青蛙来说他们的跳跃能力是一样的,如果1青蛙可以跳到的最远的点,恰巧是2青蛙能够到达的唯一一个点,只有一种可能情况,就是1青蛙能够跳到的最远的点是他前面第一个点,不然的话,只要1青蛙和最远点之间有一个点,2青蛙就可以落脚,然后就解决只有一个石头的情况,此时那块石头是1,2两只青蛙的最远点,那他俩就是你死我活的关系,所以贪心的正确性我们就yy严格的证明出来了,剩下的就跳跳跳就可以了,当然一个个跳,找最远点还是会T,所以我们需要一个神奇的$STL$:$set$,这样的话我们最终就以$O(nlogn)$的复杂度解决了这道题

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<set>
     5 #define maxn 1001000
     6 using namespace std;
     7 int t;
     8 int a[maxn];
     9 set <int> ss;
    10 int main()
    11 {
    12     scanf("%d",&t);
    13     while(t--)
    14     {
    15         int n,m,d,l,ans=0;  ss.clear();
    16         scanf("%d%d%d%d",&n,&m,&d,&l);
    17         a[1]=0;  n++;  ss.insert(0);
    18         for(int i=2;i<=n;++i)
    19         {
    20             scanf("%d",&a[i]);
    21             ss.insert(a[i]);
    22         }
    23         a[++n]=l;  ss.insert(a[n]);
    24         while(ss.size()>2)
    25         {
    26             int bj=0;
    27             set<int>::iterator qd=ss.begin();
    28             while(*qd<a[n])
    29             {
    30                 set<int>::iterator ls=--ss.upper_bound(*qd+d);
    31                 if(*ls==a[n])  {ans++;  break;}
    32                 if(*ls+d>=a[n])  {ss.erase(*ls);  ans++;  break;}
    33                 if(*ls<=*qd)  {bj=1;  break;}
    34                 qd=ls;  ss.erase(*ls);
    35             }
    36             if(bj==1)  break;
    37             if(ans==m)  break;
    38         }
    39         if(ans>=m)  printf("Excited
    ");
    40         else  printf("%d
    ",ans);
    41     }
    42     return 0;
    43 }
    View Code

    T2

    学长讲过的原题,我太废物了,不过他的线段树存的东西,我说实话考场想不到,但是其实emm,怎么说呢,想到的话其实还挺好维护的,先说一下维护什么

    struct node{
        int zuo,you;//正常线段树记录管辖范围
        int ceng;//zuo到you这个区间中一共有多少层
        ll sum;//zuo到you这么多层中一共有多少量的金坷垃
        ll cut;//zuo到you这个区间中一共要删掉前面多少层
    }a[maxm*4];

    建树的时候叶子节点正常操作,然后就是给父亲上传节点信息时的$update$操作

    void update(int f)
    {
        if(a[2*f+1].cut==0)//右儿子不删左儿子
        {
            a[f].cut=a[2*f].cut;
            a[f].ceng=a[2*f].ceng+a[2*f+1].ceng;
            a[f].sum=a[2*f].sum+a[2*f+1].sum;
        }
        else if(a[2*f+1].cut>=a[2*f].ceng)//右儿子把左儿子删完了
        {
            a[f].cut=a[2*f].cut+a[2*f+1].cut-a[2*f].ceng;//已经用左儿子抵消了右儿子的一部分cut
            a[f].ceng=a[2*f+1].ceng;//左儿子被删完了,无法作出贡献
            a[f].sum=a[2*f+1].sum;
        }
        else//删不干净左儿子
        {
            a[f].cut=a[2*f].cut;//右儿子的删除贡献被清干净了
            a[f].ceng=a[2*f].ceng+a[2*f+1].ceng-a[2*f+1].cut;//左儿子被右儿子删掉一部分
            a[f].sum=a[2*f+1].sum+cal(2*f,a[2*f+1].cut);//函数用于查询左儿子被右儿子删掉一部分之后还剩多少量
        }
    }

    接下来就是$update$函数中的$cal$函数,他实际上通过不停的询问儿子的处理,来计算右儿子删除操作对左儿子造成的影响

    int cal(int f,int w)//当前节点被删除,先删当前节点的右儿子,不够删再去删左儿子
    {
        //右儿子刚好够删,直接返回左儿子
        if(a[2*f+1].ceng==w)  return a[f].sum-a[2*f+1].sum;
        //右儿子不能被删完,就准备去删右儿子的右儿子
        if(a[2*f+1].ceng>w)  return a[f].sum-a[2*f+1].sum+cal(2*f+1,w);
        //右儿子不够删,带上删剩下的以及右儿子要删左儿子的,去删左儿子
        return cal(2*f,w-a[2*f+1].ceng+a[2*f+1].cut);
    }

    解释一下为什么左儿子不能直接写$sum$,而是用父节点-右儿子得到,因为左儿子实际上需要被右儿子删除,但当前你的左儿子中并没有计算右儿子的删除贡献,也就是说现在的左儿子的$sum$值并不真实

    剩下的就是单点修改以及查询了

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<stack>
     5 #define maxm 200100
     6 #define ll long long
     7 using namespace std;
     8 struct node{
     9     int zuo,you,ceng;
    10     ll sum,cut;
    11 }a[maxm*4];
    12 int m,q;
    13 int cal(int f,int w)
    14 {
    15     if(a[2*f+1].ceng==w)  return a[f].sum-a[2*f+1].sum;
    16     if(a[2*f+1].ceng>w)  return a[f].sum-a[2*f+1].sum+cal(2*f+1,w);
    17     return cal(2*f,w-a[2*f+1].ceng+a[2*f+1].cut);
    18 }
    19 void update(int f)
    20 {
    21     if(a[2*f+1].cut==0)
    22     {
    23         a[f].cut=a[2*f].cut;
    24         a[f].ceng=a[2*f].ceng+a[2*f+1].ceng;
    25         a[f].sum=a[2*f].sum+a[2*f+1].sum;
    26     }
    27     else if(a[2*f+1].cut>=a[2*f].ceng)
    28     {
    29         a[f].cut=a[2*f].cut+a[2*f+1].cut-a[2*f].ceng;
    30         a[f].ceng=a[2*f+1].ceng;
    31         a[f].sum=a[2*f+1].sum;
    32     }
    33     else
    34     {
    35         a[f].cut=a[2*f].cut;
    36         a[f].ceng=a[2*f].ceng+a[2*f+1].ceng-a[2*f+1].cut;
    37         a[f].sum=a[2*f+1].sum+cal(2*f,a[2*f+1].cut);
    38     }
    39 }
    40 void build(int f,int l,int r)
    41 {
    42     a[f].zuo=l;  a[f].you=r;
    43     if(l==r)
    44     {
    45         int k;  ll v;
    46         scanf("%d%lld",&k,&v);
    47         if(k==0)  {a[f].sum=v;  a[f].ceng=1;}
    48         else  a[f].cut=v;
    49         return ;
    50     }
    51     int mid=(l+r)>>1;
    52     build(2*f,l,mid);  build(2*f+1,mid+1,r);
    53     update(f);
    54 }
    55 void change(int f,int d,int opt,ll w)
    56 {
    57     if(a[f].zuo==a[f].you)
    58     {
    59         if(opt==0)  {a[f].cut=0;  a[f].sum=w;  a[f].ceng=1;}
    60         else  {a[f].sum=0;  a[f].ceng=0;  a[f].cut=w;}
    61         return ;
    62     }
    63     int mid=(a[f].zuo+a[f].you)>>1;
    64     if(d<=mid)  change(2*f,d,opt,w);
    65     else  change(2*f+1,d,opt,w);
    66     update(f);
    67 }
    68 int main()
    69 {
    70     scanf("%d%d",&m,&q);
    71     build(1,1,m);
    72     while(q--)
    73     {
    74         int c,k;  ll v;  scanf("%d%d%lld",&c,&k,&v);
    75         change(1,c,k,v);
    76         printf("%lld
    ",a[1].sum);
    77     }
    78     return 0;
    79 }
    View Code

    T3

    T3数据过水,被我用30分的代码水过了,还没理解正解,先留坑,不过话说$getchar$和$putchar$也太快了点吧,整整帮我卡掉3000毫

    暴力就他让干什么就干什么,直接模拟就可以了,我大概思考了一下,复杂度应该是$O(qn^2)$的样子,跑了11000过了

     1 //里层也需要翻
     2 #include<cstdio>
     3 #include<iostream>
     4 #define maxn 2100
     5 using namespace std;
     6 int n,m,q;
     7 char ch;
     8 char hs[maxn],hx[maxn],lz[maxn],ly[maxn];
     9 char a[maxn][maxn];
    10 int main()
    11 {
    12     scanf("%d%d%d",&n,&m,&q);
    13     for(int i=1;i<=n;++i)
    14         for(int j=1;j<=m;++j)
    15         {    
    16             ch=getchar();
    17             while(ch<'0'||ch>'9')  ch=getchar();
    18             while(ch>='0'&&ch<='9')  {a[i][j]=ch;  ch=getchar();}
    19         }
    20     while(q--)
    21     {
    22         int x,y,len,i,j;  scanf("%d%d%d",&x,&y,&len);
    23         while(len>=1)
    24         {
    25             for(i=y;i<=y+len-1;++i)  {hs[i]=a[x][i];  hx[i]=a[x+len-1][i];}
    26             for(i=x;i<=x+len-1;++i)  {lz[i]=a[i][y];  ly[i]=a[i][y+len-1];}
    27             for(i=x,j=y+len-1;i<=x+len-1,j>=y;++i,--j)  a[x][j]=lz[i];
    28             for(i=y,j=x;i<=y+len-1,j<=x+len-1;++i,++j)  a[j][y]=hx[i];
    29             for(i=x+len-1,j=y;i>=x,j<=y+len-1;--i,++j)  a[x+len-1][j]=ly[i];
    30             for(i=y+len-1,j=x+len-1;i>=y,j>=x;--i,--j)  a[j][y+len-1]=hs[i];
    31             x++;  y++;  len-=2;
    32         }
    33     }
    34     for(int i=1;i<=n;++i)
    35     {
    36         for(int j=1;j<=m;++j)  {putchar(a[i][j]);  putchar(' ');}
    37         puts("");
    38     }
    39     return 0;
    40 }
    暴力优化出奇迹
  • 相关阅读:
    mysql之创建数据库,创建数据表
    mysql之group by,order by
    一个人选出2门以上不及格的课程sql语句
    GIt入门
    数据库索引工作原理
    题目:50个人围城一圈数到3和3的倍数时出圈,问剩下的人是谁?原来的位置是多少?
    约瑟夫环:递归算法
    K-means算法的java实现,聚类分析681个三国武将
    java用一个for循环输出99乘法表
    写一个基于UDP协议的聊天小程序
  • 原文地址:https://www.cnblogs.com/hzjuruo/p/11333123.html
Copyright © 2011-2022 走看看