• 08-07 NOIP模拟测试14


    A. 旋转子段

    考场上先想到了fhq的区间翻转,然而并没用从fhq的操作中找到什么解题的思路,又这道题数据范围一看就不能真去翻转,然后很快就算把这个弃掉了。

    之后又想到一些神奇的东西,比如说我把i与a[i]做差得到下标是i的新数组,它的含义是我这个元素离我要去的固定点差多少,或者相反的,表示我要去哪。

    然后就发现最优情况是新数组的最长的满足旋转性质的回文字串,性质即是 -2 0 2 这种特定的串,然后就想先预处理出这些串,为了查询,把它们hash掉放到哈希表里。

    过了几秒就发现自己又**忘了题意开始自己瞎YY了,我找完全回文串有个毛用啊#$%#%@。

    然后想清清脑子先放一放,打了个$Theta (n^3)$ 暴力走了。

    正解:

    假设我们有一段区间[i,j],如果a[i]!=j&&a[j]!=i,i j都不能通过这次旋转变成固定点,那我为什么不旋转[i+1,j-1]?

    我们一直在上面的判断不成立的时候去掉两端,最终会得到a[i]==j||a[j]==i,相当于是这种贡献的最简表达形式。

    然后我们就知道了对于一个答案的贡献区间一共有n个,分别为$ [min(i,a[i]),max(i,a[i])] $。

    得到了这个性质,我们考虑计算。

    把每个贡献拆成三段,[i,l-1],[l,r],[r+1,n]。对于两侧的静态答案可以用前缀和$ Theta (N) $ 处理,直接$ Theta (1) $查

    对于[l,r],我们发现对于所有区间内的固定点j满足 a[j]+j==a[i]+i,含义上理解就是a[i]与i a[j]与j关于同一条轴对称,所以翻转后a[j]到了j就成了固定点。

    所以可以建桶,把区间内的a[j]+j装进桶里,然后用a[i]+i查询即可。

    然而暴力装桶复杂度是n2的。有以下算法优化:

    卡常可A算法一:莫队

    套路离线排序直接瞎搞即可。

    想卡过需要以下:奇偶排序,预处理前缀和,预处理每个询问左端点所在块(很重要)fh。

    算法二:这是正解

    对于轴心分类建vector存轴心为这个点的区间,每个vector按区间长度从大到小排序。

    这样我们对于一个区间,直接查下vec[i].size()-j就能得到[l,r]的'桶'。

    正确性:其实上面有说,因为a[j]+j和a[i]+i关于同一个轴对称,我查这个轴且区间长度比i小的就直接能查到$ sumlimits a[j]+j $。

    而a[j]+j其实也是我们要的一个贡献区间,所以我们一直操作下去即可。

    由于只有n个区间,这个看似O(n2)的算法其实是O(n)的

     1 #include<cstdio>
     2 #include<cmath>
     3 #include<algorithm>
     4 #define reg register
     5 #define F(i,a,b) for(register int (i)=(a);(i)<=(b);++(i))
     6 const int L=1<<20|1;
     7 char buffer[L],*S,*T;
     8 #define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++)
     9 using namespace std;
    10 int read();
    11 const int N=500005;
    12 int n,t;
    13 int a[N];
    14 int sum[N];
    15 int bk[N<<1];
    16 struct Q{
    17     int id,l,r,bl;
    18     friend bool operator<(const Q &a,const Q &b)
    19     {
    20         return a.bl==b.bl?((a.bl&1)?a.r<b.r:a.r>b.r):a.bl<b.bl;
    21     }
    22 }q[N];
    23 int main()
    24 {
    25     n=read();
    26     t=pow(n,0.53);
    27     F(i,1,n)
    28     {
    29         a[i]=read();
    30         sum[i]=sum[i-1]+(a[i]==i);
    31     }
    32     F(i,1,n)
    33     {
    34         q[i].l=min(i,a[i]);
    35         q[i].r=max(i,a[i]);
    36         q[i].bl=q[i].l/t;
    37         q[i].id=i;
    38     }
    39     sort(q+1,q+n+1);
    40     reg int l=1,r=0,ans=1;
    41     F(i,1,n)
    42     {
    43         if(sum[q[i].l-1]+sum[n]-sum[q[i].r]+(q[i].r-q[i].l+1)<=ans) continue;
    44         while(l<q[i].l)
    45         {
    46             --bk[a[l]+l];
    47             ++l;
    48         }
    49         while(l>q[i].l)
    50         {
    51             --l;
    52             ++bk[a[l]+l];
    53         }
    54         while(r<q[i].r)
    55         {
    56             ++r;
    57             ++bk[a[r]+r];
    58         }
    59         while(r>q[i].r)
    60         {
    61             --bk[a[r]+r];
    62             --r;
    63         }
    64         ans=max(ans,sum[q[i].l-1]+sum[n]-sum[q[i].r]+bk[a[q[i].id]+q[i].id]);
    65         if(ans==n) break;
    66     }
    67     printf("%d
    ",ans);
    68     return 0;
    69 }
    70 int read()
    71 {
    72     reg int x=0;
    73     reg char tc=getchar();
    74     while(tc<'0'||tc>'9') tc=getchar();
    75     while(tc>='0'&&tc<='9') x=x*10+tc-48,tc=getchar();
    76     return x;
    77 }
    莫队
     1 #include<cstdio>
     2 #include<cmath>
     3 #include<vector>
     4 #include<algorithm>
     5 #define reg register
     6 #define F(i,a,b) for(register int (i)=(a);(i)<=(b);++(i))
     7 //const int L=1<<20|1;
     8 //char buffer[L],*S,*T;
     9 //#define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++)
    10 using namespace std;
    11 int read();
    12 const int N=500005;
    13 int n,t;
    14 int a[N];
    15 int sum[N];
    16 vector<int> q[N<<1];
    17 bool cmp(int a,int b)
    18 {
    19     return a>b;
    20 }
    21 int main()
    22 {
    23     n=read();
    24     F(i,1,n)
    25     {
    26         a[i]=read();
    27         sum[i]=sum[i-1]+(a[i]==i);
    28     }
    29     int l,r;
    30     F(i,1,n)
    31     {
    32         l=min(i,a[i]);
    33         r=max(i,a[i]);
    34         q[l+r].push_back(r-l+1);
    35     }
    36     int lim=n<<1;
    37     F(i,2,lim)
    38     {
    39         sort(q[i].begin(),q[i].end(),cmp);
    40     }
    41     int ans=1;
    42     F(i,2,lim)
    43     {
    44         for(reg int j=0;j<q[i].size();++j)
    45         {
    46             r=(q[i][j]+i-1)>>1;
    47             l=i-r;
    48             ans=max(ans,sum[l-1]+sum[n]-sum[r]+(int)q[i].size()-j);
    49         }
    50     }
    51     printf("%d
    ",ans);
    52     return 0;
    53 }
    54 int read()
    55 {
    56     reg int x=0;
    57     reg char tc=getchar();
    58     while(tc<'0'||tc>'9') tc=getchar();
    59     while(tc>='0'&&tc<='9') x=x*10+tc-48,tc=getchar();
    60     return x;
    61 }
    vector

    B. 走格子

     鲜鮕亿下...

    这题一眼看上去就像是个搜索加剪枝,然而我就真的这么以为了。

    其实从优化搜索的角度,使用传送门,就相当与花费里我最近的墙的距离+1,而到达以我为中心向四个方向正对的墙前一个格子。

    然后就能发现这个搜索已经没有必要了,直接建好图跑dij就好了。

    建图:

    1.我向四个方向的非墙格子,权值1

    2.我向四个方向正对的墙前一个格子,权值离我最近的墙+1

    然后这题没了。

      1 #include<cstdio>
      2 #include<cstring>
      3 #include<vector>
      4 #include<cmath>
      5 #include<queue>
      6 #include<algorithm>
      7 #define ll long long
      8 #define reg register
      9 #define F(i,a,b) for(register int (i)=(a);(i)<=(b);++(i))
     10 using namespace std;
     11 void find_wall();
     12 const int N=505;
     13 int n,m;
     14 int z[N][N],id[N][N],cnt;
     15 int tx[5]={0,1,0,-1},ty[5]={1,0,-1,0};
     16 int near[N][N];
     17 int temp[N];
     18 int dis[N*N];
     19 bool vis[N*N];
     20 int st_x,st_y,ed_x,ed_y;
     21 struct node{
     22     int x,y,step;
     23 };
     24 struct DJ{
     25     int id,dis;
     26     friend bool operator<(const DJ &a,const DJ &b)
     27     {
     28         return a.dis>b.dis;
     29     }
     30 };
     31 priority_queue<DJ> q;
     32 queue<node> bq;
     33 int fir[N*N],o=1;
     34 struct R{
     35     int u,v,w,next;
     36 }r[19260817];
     37 void add(int u,int v,int w)
     38 {
     39     if(u==v) return;
     40     r[++o].u=u;
     41     r[o].v=v;
     42     r[o].w=w;
     43     r[o].next=fir[u];
     44     fir[u]=o;
     45 }
     46 void dj()
     47 {
     48     dis[id[st_x][st_y]]=0;
     49     q.push((DJ){id[st_x][st_y],0});
     50     int u;
     51     while(!q.empty())
     52     {
     53         u=q.top().id;
     54         q.pop();
     55         if(vis[u]) continue;
     56         vis[u]=1;
     57         for(reg int i=fir[u];i;i=r[i].next)
     58         {
     59             int v=r[i].v;
     60             if(dis[v]>dis[u]+r[i].w)
     61             {
     62                 dis[v]=dis[u]+r[i].w;
     63                 q.push((DJ){v,dis[v]});
     64             }
     65         }
     66     }
     67 }
     68 void bfs()
     69 {
     70     reg int x,y,step;
     71     while(!bq.empty())
     72     {
     73         x=bq.front().x;
     74         y=bq.front().y;
     75         step=bq.front().step;
     76         bq.pop();
     77         if(near[x][y]!=0x3f3f3f3f) continue;
     78         if(z[x][y])
     79         {
     80             near[x][y]=step;
     81         }
     82         F(i,0,3)
     83         {
     84             int nx,ny;
     85             nx=x+tx[i];
     86             ny=y+ty[i];
     87             if(z[nx][ny]==0) continue;
     88             bq.push((node){nx,ny,step+1});
     89         }
     90     }
     91 }
     92 void build()
     93 {
     94     F(x,1,n)
     95     {
     96         F(y,1,m)
     97         {
     98             if(z[x][y]==0||z[x][y]==3) continue;
     99             F(i,0,3)
    100             {
    101                 int nx,ny;
    102                 nx=x+tx[i];
    103                 ny=y+ty[i];
    104                 if(z[nx][ny])
    105                 {
    106                     add(id[x][y],id[nx][ny],1);
    107                 }
    108             }
    109         }
    110     }
    111     find_wall();
    112 }
    113 void find_wall()
    114 {
    115     int wall=1;
    116     F(i,1,n)
    117     {
    118         F(j,1,m)
    119         {
    120             if(z[i][j]==0) wall=j;
    121             else add(id[i][j],id[i][wall+1],near[i][j]);        //pan 自环
    122         }
    123         for(reg int j=m;j>=1;--j)
    124         {
    125             if(z[i][j]==0) wall=j;
    126             else add(id[i][j],id[i][wall-1],near[i][j]);
    127         }
    128     }
    129     F(j,1,m)
    130     {
    131         F(i,1,n)
    132         {
    133             if(z[i][j]==0) wall=i;
    134             else add(id[i][j],id[wall+1][j],near[i][j]);
    135         }
    136         for(reg int i=n;i>=1;--i)
    137         {
    138             if(z[i][j]==0) wall=i;
    139             else add(id[i][j],id[wall-1][j],near[i][j]);
    140         }
    141     }
    142 }
    143 int main()
    144 {
    145     memset(dis,0x3f,sizeof(dis));
    146     memset(near,0x3f,sizeof(near));
    147     scanf("%d %d",&n,&m);
    148     F(i,1,n)
    149     {
    150         F(j,1,m)
    151         {
    152             char tc=getchar();
    153             while(tc!='#'&&tc!='.'&&tc!='C'&&tc!='F') tc=getchar();
    154             if(tc=='#')
    155             {
    156                 z[i][j]=0;
    157                 bq.push((node){i,j,0});
    158             }
    159             else if(tc=='.') z[i][j]=1;
    160             else if(tc=='C')
    161             {
    162                 st_x=i;
    163                 st_y=j;
    164                 z[i][j]=2;
    165             }
    166             else if(tc=='F')
    167             {
    168                 ed_x=i;
    169                 ed_y=j;
    170                 z[i][j]=3;
    171             }
    172             if(z[i][j]) id[i][j]=++cnt;
    173         }
    174     }
    175     bfs();
    176     build();
    177 /*    F(i,1,n)
    178     {
    179         F(j,1,m)
    180         {
    181             if(near[i][j]==0x3f3f3f3f) putchar('-');
    182             else printf("%d",near[i][j]);
    183         }
    184         puts("");
    185     }*/
    186     dj();
    187 //    F(i,1,cnt) printf("%d
    ",dis[i]);
    188     if(!vis[id[ed_x][ed_y]]) puts("no");
    189     else printf("%d
    ",dis[id[ed_x][ed_y]]);
    190     return 0;
    191 }
    View Code

    C. 柱状图

    yy了下觉得高度可以三分,然后脑抽觉得位置也可以。然后就码了个三分套三分套O(n)验证。

    后来又码了个拍,发现拍个几组就会出错,且答案相差不多。

    再想便发现是位置不满足单峰函数,脑补下w。

    然后对高度三分跑拍,验证正确性get。

    如果不加外层三分,复杂度就会到达。O(n2log1.5n)

    由于它的正确率较高,我打算直接测试点分治让它跑大点。

    于是拿到了80分,其中应该有10是TLE。

    skyh 也对位置进行了三分,但他通过预处理

  • 相关阅读:
    mysql数据库 --数据类型、约束条件
    并发编程 --线程
    并发编程 --进程
    MySQL数据库 --基础
    网络编程之 TCP-UDP的详细介绍
    网络编程之 OSI七层协议
    python 元类、单例模式
    python 面向对象_多态、内置方法、反射
    Python 面向对象_继承、组合
    简单工厂设计模式
  • 原文地址:https://www.cnblogs.com/hzoi-yzh/p/11320395.html
Copyright © 2020-2023  润新知