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

    这套题总的来说,由于出题人的数据非常水,所以我用各种方法水了过去

    T1

    暴搜+剪枝

    剪枝一

    如果$gcd$已经变成了1那么就没有继续走下去的必要,直接用最长序列长度尝试更新答案,然后直接$break$即可

    剪枝二

    如果你当前的$gcd$乘上最长的区间长度,对答案也不能作出贡献,那么你已经用了最长序列长度,且越往后走$gcd$会变的越小,那么答案永远不会变优,就也没有继续下去的必要了,$break$即可

    然后就水过这道题

     1 #include<iostream>
     2 #include<cstdio>
     3 #define maxn 100100
     4 #define int long long
     5 using namespace std;
     6 int n,ans;
     7 int a[maxn];
     8 int gcd(int a,int b)
     9 {
    10     return b==0?a:gcd(b,a%b);
    11 }
    12 signed main()
    13 {
    14     //freopen("1.in","r",stdin);
    15     scanf("%lld",&n);
    16     for(int i=1;i<=n;++i)  scanf("%lld",&a[i]);
    17     for(int i=1;i<=n;++i)
    18     {
    19         int GCD=a[i];
    20         for(int j=i+1;j<=n;++j)
    21         {
    22             GCD=gcd(GCD,a[j]);
    23             if(GCD*(n-i+1)<=ans)  break;
    24             if(GCD==1)  {ans=max(ans,n-i+1);  break;}
    25             ans=max(ans,GCD*(j-i+1));
    26         }
    27     }
    28     printf("%lld
    ",ans);
    29     return 0;
    30 }
    View Code

    正解直接贴了

    T2

    考场上用假贪心水过去了,出题人的数据造的太水了,大家以各种姿势水过了这道题

    这样就已经可以过了

     1 #include<iostream>
     2 #include<cstdio>
     3 #define LL long long
     4 using namespace std;
     5 const int N=100010;
     6 const LL inf=1e12;
     7 int n,q;
     8 LL ans;
     9 LL a[N],b[N],ma1[N],ma2[N],mi1[N],mi2[N];
    10 int read()
    11 {
    12     int s=0;char c=getchar();
    13     while(c<'0'||c>'9')  c=getchar();
    14     while(c>='0'&&c<='9')  {s=(s<<3)+(s<<1)+c-'0';  c=getchar();}
    15     return s;
    16 }
    17 int main()
    18 {
    19     n=read();ans=inf;
    20     for(int i=1;i<=n;i++)  {a[i]=read();b[i]=read();}
    21     mi1[0]=mi2[0]=inf;
    22     for(int i=1;i<=n;i++){
    23         LL x=min(a[i],b[i]);  LL y=max(a[i],b[i]);
    24         mi1[0]=min(mi1[0],x);  ma1[0]=max(ma1[0],x);
    25         mi2[0]=min(mi2[0],y);  ma2[0]=max(ma2[0],y);
    26     }
    27     ans=(ma1[0]-mi1[0])*(ma2[0]-mi2[0]);  printf("%lld
    ",ans);
    28     return 0;
    29 }

    我的贪心在$O(n^2)$的时候是没有问题的,但是他依旧会T,我就乱搞了一下,他就A了

    我的贪心思路是枚举每一个小球,找到和它差值最小的n-1个球放进一堆

    正解还是粘吧

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 using namespace std;
     5 #define ll long long
     6 #define maxn 100010
     7 #define inf 2000000000000000000
     8 int n,ls1,ls2;
     9 ll hzma1[maxn],hzmi1[maxn],qzma1[maxn],qzmi1[maxn];//x一列
    10 ll hzma2[maxn],hzmi2[maxn],qzma2[maxn],qzmi2[maxn];//y一列
    11 ll R,r=inf,B,b=inf,ans=inf;
    12 struct node{
    13     ll x,y;
    14 }q[maxn];
    15 int main()
    16 {
    17     scanf("%d",&n);
    18     for(int i=1;i<=n;++i) 
    19     {
    20         scanf("%lld%lld",&q[i].x,&q[i].y);
    21         ls1=min(q[i].x,q[i].y); ls2=max(q[i].x,q[i].y);
    22         q[i].x=ls1; q[i].y=ls2;
    23         R=max(R,q[i].x); r=min(r,q[i].x);
    24         B=max(B,q[i].y); b=min(b,q[i].y);
    25     }
    26     ans=(R-r)*(B-b); //cout<<ans<<endl;
    27     memset(qzmi1,0x7f,sizeof(qzmi1)); memset(hzmi1,0x7f,sizeof(hzmi1));
    28     memset(qzmi2,0x7f,sizeof(qzmi2)); memset(hzmi2,0x7f,sizeof(hzmi2));
    29     for(int i=1;i<=n;++i) 
    30     {
    31         qzmi1[i]=min(qzmi1[i-1],q[i].x);
    32         qzma1[i]=max(qzma1[i-1],q[i].x);
    33         qzmi2[i]=min(qzmi2[i-1],q[i].y);
    34         qzma2[i]=max(qzma2[i-1],q[i].y);
    35     }
    36     for(int i=n;i>=1;--i) 
    37     {
    38         hzmi1[i]=min(hzmi1[i+1],q[i].x);
    39         hzma1[i]=max(hzma1[i+1],q[i].x);
    40         hzmi2[i]=min(hzmi2[i+1],q[i].y);
    41         hzma2[i]=max(hzma2[i+1],q[i].y);
    42     }
    43     for(int i=2;i<=n;++i)
    44     {
    45         if(qzmi2[i-1]<q[i].x) break;
    46         R=max(qzma2[i-1],hzma1[i]); r=min(qzmi2[i-1],hzmi1[i]);
    47         B=max(qzma1[i-1],hzma2[i]); b=min(qzmi1[i-1],hzmi2[i]);
    48         ans=min(ans,(R-r)*(B-b));
    49     }
    50     printf("%lld",ans);
    51     return 0;
    52 }
    放个正解代码就溜了

    T3

    又是线段树优化DP,最近老是见到他,还是先考虑最简单的DP,设$f[i][j][k]$代表第$i$轮,两个指针分别在$j$和$k$的最小移动距离,转移的话让两个指针都分别动一下,设$p[i]$代表第$i$轮要在的位置,那么$f[i][p[i]][k]=min(f[i][p[i]][k],f[i-1][j][k]+abs(j-p[i]))$,$f[i][j][p[i]]=min(f[i][j][p[i]],f[i-1][j][k]+abs(k-p[i]))$,数组开不到把第一维滚起来就可以了,然而,这种$O(n^3)$的非常不优秀算法,依旧会得到$T0$的好成绩,考虑一下,除了滚动之外,我们是不是可以省掉后面两维中的某一维,我们会发现,除了初始状态之外,剩余所有状态,都有一个指针在$p[i]$的位置,所以有一维是和$i$直接相关的,我们可以省掉他,现在dp数组就变成了$f[i][j]$,代表第$i$轮,一个指针在$j$的位置上,另一个指针在$p[i]$的位置上的最小移动距离,转移的话一个是在上一轮在$p[i-1]$的位置上挪过来,另一种是不在$p[i-1]$的位置上挪过来,如果在$p[i-1]$的位置上挪过来那么$f[i][j]=min(f[i][j],f[i-1][j]+abs(p[i-1]-j))$,如果不在$p[i-1]$的位置上挪过来,那么$f[i][p[i-1]]=min(f[i][p[i-1]],f[i-1][j]+abs(j-p[i]))$,这样的话,转移就变成了$O(n^2)$的dp,依旧过不太去,考虑一下他的转移可以对应线段树中的区间加,区间最小值查询,单点修改,那么我们就把这个dp摁到线段树上去,由于我们有个$abs$的存在,所以线段树维护最小值,同时需要$f[i][j]-j$和$f[i][j]+j$,就都维护了,把$p[i]$和$j$的大小分情况,去线段树查询区间最小值即可

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 #include<cmath>
      5 #define maxn 100100
      6 #define int long long
      7 #define inf 2000000000000000000
      8 using namespace std;
      9 struct node{
     10     int zuo,you,w,lan,zxa/*+j*/,zxn/*-j*/;
     11 }a[maxn<<2];
     12 int n,q,A,B,ans=inf;
     13 int p[maxn];
     14 void up(int fa)
     15 {
     16     a[fa].w=min(a[2*fa].w,a[2*fa+1].w);
     17     a[fa].zxa=min(a[2*fa].zxa,a[2*fa+1].zxa);
     18     a[fa].zxn=min(a[2*fa].zxn,a[2*fa+1].zxn);
     19 }
     20 void down(int fa)
     21 {
     22     a[2*fa].w+=a[fa].lan;  a[2*fa+1].w+=a[fa].lan;
     23     a[2*fa].zxa+=a[fa].lan;  a[2*fa+1].zxa+=a[fa].lan;
     24     a[2*fa].zxn+=a[fa].lan;  a[2*fa+1].zxn+=a[fa].lan;
     25     a[2*fa].lan+=a[fa].lan;  a[2*fa+1].lan+=a[fa].lan;
     26     a[fa].lan=0;
     27 }
     28 void build(int fa,int l,int r)
     29 {
     30     a[fa].zuo=l;  a[fa].you=r;  a[fa].w=inf;  a[fa].zxa=inf;  a[fa].zxn=inf;
     31     if(l==r)
     32     {
     33         if(l==A)  {int ls=abs(p[1]-B);  a[fa].w=min(a[fa].w,ls);}
     34         if(l==B)  {int ls=abs(p[1]-A);  a[fa].w=min(a[fa].w,ls);}
     35         a[fa].zxa=a[fa].w+a[fa].zuo;  a[fa].zxn=a[fa].w-a[fa].zuo;
     36         return ;
     37     }
     38     int mid=(l+r)>>1;
     39     build(2*fa,l,mid);  build(2*fa+1,mid+1,r);  up(fa);
     40 }
     41 void add(int fa,int l,int r,int w)
     42 {
     43     if(a[fa].zuo>=l&&a[fa].you<=r)
     44     {
     45         a[fa].w+=w;  a[fa].zxa+=w;  a[fa].zxn+=w;  a[fa].lan+=w;
     46         return ;
     47     }
     48     if(a[fa].lan)  down(fa);
     49     int mid=(a[fa].zuo+a[fa].you)>>1;
     50     if(l<=mid)  add(2*fa,l,r,w);
     51     if(r>mid)  add(2*fa+1,l,r,w);
     52     up(fa);
     53 }
     54 void change(int fa,int pos,int w)
     55 {
     56     if(a[fa].zuo==a[fa].you)
     57     {
     58         a[fa].w=w;  a[fa].zxa=w+a[fa].zuo;  a[fa].zxn=w-a[fa].zuo;
     59         return ;
     60     }
     61     if(a[fa].lan)  down(fa);
     62     int mid=(a[fa].zuo+a[fa].you)>>1;
     63     if(pos<=mid)  change(2*fa,pos,w);
     64     else  change(2*fa+1,pos,w);
     65     up(fa);
     66 }
     67 int query1(int fa,int l,int r)//-j
     68 {
     69     if(a[fa].zuo>=l&&a[fa].you<=r)  return a[fa].zxn;
     70     if(a[fa].lan)  down(fa);
     71     int mid=(a[fa].zuo+a[fa].you)>>1,minn=inf;
     72     if(l<=mid)  minn=min(minn,query1(2*fa,l,r));
     73     if(r>mid)  minn=min(minn,query1(2*fa+1,l,r));
     74     return minn;
     75 }
     76 int query2(int fa,int l,int r)//+j
     77 {
     78     if(a[fa].zuo>=l&&a[fa].you<=r)  return a[fa].zxa;
     79     down(fa);
     80     int mid=(a[fa].zuo+a[fa].you)>>1,minn=inf;
     81     if(l<=mid)  minn=min(minn,query2(2*fa,l,r));
     82     if(r>mid)  minn=min(minn,query2(2*fa+1,l,r));
     83     return minn;
     84 }
     85 void upp(int fa)
     86 {
     87     if(a[fa].zuo==a[fa].you)  return ;
     88     down(fa);  upp(2*fa);  upp(2*fa+1);  up(fa);
     89 }
     90 signed main()
     91 {
     92     //freopen("3.in","r",stdin);
     93     //freopen("W.out","w",stdout);
     94     scanf("%lld%lld%lld%lld",&n,&q,&A,&B);
     95     for(int i=1;i<=q;++i)  scanf("%lld",&p[i]);
     96     build(1,1,n);
     97     for(int i=2;i<=q;++i)
     98     {
     99         int minn=query1(1,1,p[i])+p[i];
    100         minn=min(minn,query2(1,p[i]+1,n)-p[i]);
    101         add(1,1,n,abs(p[i]-p[i-1]));  change(1,p[i-1],minn);
    102     }
    103     upp(1);  printf("%lld
    ",a[1].w);
    104     return 0;
    105 }
    View Code
  • 相关阅读:
    JS 可选链操作符?. 空值合并运算符?? 详解,更精简的安全取值与默认值设置小技巧
    手写一个 Promise
    Leetcode 403 青蛙过河 DP
    Leeetcode 221 最大正方形 DP
    Leetcode 139 单词拆分
    Unity周记: 2021.07.26-08.15
    Unity周记: 2021.07.19-07.25
    Unity周记: 2020.07.12-07.18
    Unity周记: 2020.07.05-07.11
    线性规划
  • 原文地址:https://www.cnblogs.com/hzjuruo/p/11644373.html
Copyright © 2011-2022 走看看