zoukankan      html  css  js  c++  java
  • 模拟12题解

    T1[A. 斐波那契(fibonacci)]

    考场上发现了一个性质:一个节点的父节点=该节点编号-上一个fibonacci数

    所以求父亲节点代码

    int fa(int x)
    {
        for(int i=mx;i;i--)
            if(fi[i]<x)
                return x-fi[i];
    }

    然后我只想到了建树的70%代码,数组越界了又少了30分QAQ

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<queue>
     6 #define int long long
     7 using namespace std;
     8 inline int read()
     9 {
    10     int f=1,x=0;char ch=getchar();
    11     while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    12     while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    13     return f*x;
    14 }
    15 const int mx=65;
    16 const int maxn=1000000;
    17 int fi[mx+10];
    18 int d[maxn+5];
    19 int f[maxn+5][25];
    20 struct node{
    21     int v,nxt;
    22 }e[maxn];int h[maxn],nu;
    23 void add(int x,int y)
    24 {
    25     e[++nu].v=y;
    26     e[nu].nxt=h[x];
    27     h[x]=nu;
    28 }
    29 int gfa(int x)
    30 {
    31     for(int i=mx;i;i--)
    32         if(fi[i]<x)
    33             return x-fi[i];
    34 }
    35 void bfs()
    36 {
    37     queue<int>q;
    38     d[1]=1;
    39     q.push(1);
    40     while(q.size())
    41     {
    42         int x=q.front();q.pop();
    43         for(int i=h[x];i;i=e[i].nxt)
    44         {
    45             int y=e[i].v;
    46             if(d[y])continue;
    47             d[y]=d[x]+1;
    48             f[y][0]=x;
    49             for(int j=1;j<=21;j++)
    50                 f[y][j]=f[f[y][j-1]][j-1];
    51             q.push(y);
    52         }
    53     }
    54 }
    55 int lca(int x,int y)
    56 {
    57     if(d[x]>d[y])swap(x,y);
    58     for(int i=21;i>=0;i--)
    59         if(d[f[y][i]]>=d[x])
    60             y=f[y][i];
    61     if(y==x)return x;
    62     for(int i=21;i>=0;i--)
    63         if(f[x][i]!=f[y][i])
    64             x=f[x][i],y=f[y][i];
    65     return f[x][0];    
    66 }
    67 signed main()
    68 {
    69     //freopen("fibonacci2.in","r",stdin);
    70     int m=read(),mxx;
    71     fi[0]=fi[1]=1;
    72     for(int i=2;i<=mx;i++)
    73         fi[i]=fi[i-1]+fi[i-2];
    74     for(int i=2;i<=maxn;i++)
    75     {
    76         int fa=gfa(i);
    77         add(fa,i);
    78     }
    79     bfs();
    80     for(int i=1;i<=m;i++)
    81     {
    82         int x=read(),y=read();
    83         printf("%lld
    ",lca(x,y));
    84     }
    85 }
    86 /*
    87 g++ 1.cpp -o 1
    88 ./1
    89 
    90 */
    View Code

    可是考完才发现暴力既好写,又能A

    对于输入的两个节点x,y将其中一个向上遍历,并把经过的路径都存入一个vector

    然后另一个向上翻,如果在vector中能找到,那此时的y就是答案

    时间复杂度$O(60mlog(n))$

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<queue>
     6 #include<vector>
     7 #define int long long
     8 using namespace std;
     9 inline int read()
    10 {
    11     int f=1,x=0;char ch=getchar();
    12     while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    13     while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    14     return f*x;
    15 }
    16 const int mx=65;
    17 int fi[mx+10];
    18 int fa(int x)
    19 {
    20     for(int i=mx;i;i--)
    21         if(fi[i]<x)
    22             return x-fi[i];
    23 }
    24 signed main()
    25 {
    26     //freopen("data","r",stdin);
    27     int m=read();
    28     fi[0]=fi[1]=1;
    29     for(int i=2;i<=mx;i++)
    30         fi[i]=fi[i-1]+fi[i-2];
    31     vector<int>v;
    32     for(int i=1;i<=m;i++)
    33     {
    34         int x=read(),y=read();
    35         v.clear();
    36         while(x>1)
    37         {
    38             v.push_back(x);
    39             x=fa(x);
    40         }
    41         while(y>1)
    42         {
    43             vector<int>::iterator res=find(v.begin(),v.end(),y);
    44             if(res!=v.end())  break;
    45             y=fa(y);
    46         }
    47         printf("%lld
    ",y);
    48     }
    49 }
    50 /*
    51 g++ 1.cpp -o 1
    52 ./1
    53 
    54 */
    View Code

    vector中查找元素:

    vector<int>::iterator res=find(v.begin(),v.end(),y);//在v中查找y
    if(res!=v.end()) //找到了 

    T2[B. 数颜色]「排序」「线段树」「分块」「莫队」

    考场上只想到了$O(nm)$的纯暴力,

    然而以上的这些都能拿到不少的部分分,更有主席树,树套树的高超方法,我却什么都搞不出来

    65%+算法:动态开点线段树

    考试时想用线段树,当时的思维是这样的:死板地维护区间1-n,然后查询。。。打到一半,诶,查询什么?线段树里开3e5个颜色的个数,不可能的。。。

    然后就傻了,想想其他的数据结构我也没法维护。。

    殊不知,,我"忘"了一个叫权值线段树的东西,动态开点,每棵树维护每种color的在原区间的个数,时空复杂度$O(nlog(n))$

    使用动动的代码:

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int n,m;
     4 int a[300001];
     5 int rt[300001],trsum[10000000],son[10000000][2],tot;
     6 void change(int &x,int l,int r,int to,int d)
     7 {
     8     if(!x)x=++tot;
     9     trsum[x]+=d;
    10     if(l==r)return;
    11     int mid=(l+r)>>1;
    12     if(to<=mid)change(son[x][0],l,mid,to,d);
    13     else change(son[x][1],mid+1,r,to,d);
    14 }
    15 int ask(int x,int l,int r,int L,int R)
    16 {
    17     if(!x)return 0;
    18     if(l==L&&r==R)return trsum[x];
    19     int mid=(l+r)>>1;
    20     if(L>mid)return ask(son[x][1],mid+1,r,L,R);
    21     else if(R<=mid)return ask(son[x][0],l,mid,L,R);
    22     else return ask(son[x][0],l,mid,L,mid)+ask(son[x][1],mid+1,r,mid+1,R);
    23 }
    24 int main()
    25 {
    26     scanf("%d%d",&n,&m);
    27     for(int i=1;i<=n;i++)
    28     {
    29         scanf("%d",&a[i]);
    30         change(rt[a[i]],1,n,i,1);
    31     }
    32     while(m--)
    33     {
    34         int opt;
    35         scanf("%d",&opt);
    36         if(opt==1)
    37         {
    38             int l,r,c;
    39             scanf("%d%d%d",&l,&r,&c);
    40             printf("%d
    ",ask(rt[c],1,n,l,r));
    41         }
    42         else
    43         {
    44             int x;
    45             scanf("%d",&x);
    46             change(rt[a[x  ]],1,n,x  ,-1);
    47             change(rt[a[x  ]],1,n,x+1, 1);
    48             change(rt[a[x+1]],1,n,x+1,-1);
    49             change(rt[a[x+1]],1,n,x  , 1);
    50             a[x]^=a[x+1]^=a[x]^=a[x+1];
    51         }
    52     }
    53     return 0;
    54 }
    View Code

    65%+算法:分块

    我现在已经想不起来我当时怎么把分块给否了的,可能当时粗略一想空间不够,但是分完块就没几块了,复杂度$O(msqrt{n})$这么直接的算法我也想不到,想得严密一些不要轻易就放弃自己的想法

    正解:

    将(颜色,位置)按照二元组排序,对于查询操作,使用结构体lower_bound二分查找

    对于修改操作,暴力修改结构体的pos,

    注意若两个颜色不同,那么修改不会改变每个颜色块里的顺序

    若相同,不用修改

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define mid ((l+r)>>1)
     6 using namespace std;
     7 const int maxn=3e5+5;
     8 inline int read()
     9 {
    10     int f=1,x=0;char ch=getchar();
    11     while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    12     while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    13     return f*x;
    14 }
    15 int n,sum[maxn],jl[maxn]; 
    16 struct node{
    17     int pos,da;
    18 }a[maxn];
    19 bool cmp(node x,node y){return (x.da==y.da)?x.pos<y.pos:x.da<y.da;}
    20 int main()
    21 {
    22 //    freopen("data","r",stdin);
    23     n=read();int Q=read(),mc=0;
    24     for(int i=1;i<=n;i++)
    25     {
    26         a[i].da=read(),a[i].pos=i;
    27         sum[a[i].da]++;
    28         mc=max(mc,a[i].da);
    29         jl[i]=a[i].da;
    30     }
    31     for(int i=1;i<=mc;i++)
    32         sum[i]+=sum[i-1];
    33     sort(a+1,a+n+1,cmp);
    34     while(Q--)
    35     {
    36         int opt=read();
    37         if(opt==1)
    38         {
    39             int L=read(),R=read(),col=read();
    40             node l,r;
    41             l.da=col,l.pos=L;
    42             r.da=col,r.pos=R;
    43             int ll=lower_bound(a+sum[col-1]+1,a+sum[col]+1,l,cmp)-a;
    44             int rr=upper_bound(a+sum[col-1]+1,a+sum[col]+1,r,cmp)-a;
    45             printf("%d
    ",rr-ll);
    46         }
    47         if(opt==2)
    48         {
    49             int i=read();
    50             int x=i,y=i+1;
    51             if(jl[x]==jl[y])continue;
    52             node xx,yy;
    53             xx.pos=x,xx.da=jl[x];int c1=jl[x];
    54             yy.pos=y,yy.da=jl[y];int c2=jl[y];
    55             int xp=lower_bound(a+sum[c1-1]+1,a+sum[c1]+1,xx,cmp)-a;
    56             int yp=lower_bound(a+sum[c2-1]+1,a+sum[c2]+1,yy,cmp)-a;
    57             a[xp].pos=y,a[yp].pos=x;
    58             jl[x]=yy.da,jl[y]=xx.da;
    59         }
    60     }
    61 }
    62 /*
    63 g++ 2.cpp -o 2
    64 ./2
    65 
    66 */
    View Code

    结构体lower_bound:

    bool cmp(node x,node y){return (x.da==y.da)?x.pos<y.pos:x.da<y.da;}
    int ll=lower_bound(a+1,a+n+1,l,cmp)-a;//a中查找l返回下标ll

    T3[C. 分组]「二分图」

    性质:若要保证字典序最小,则从后往前枚举,让每一段区间尽量长,那么可以保证字典序最小

    k==1时,从后往前枚举,看枚举到的点与已有的点有无矛盾,若有则该点为断点

    k==2时,同样的枚举方式对于枚举到的点的判断方式:

    每段区间就是一个二分图,

    1:若三者互相矛盾 ,那么当枚举到第三个时,发现第三个与其中一个放不到两边,设置为断点

    2:若有两个相同的颜色,第三个不同颜色,枚举到的第三个是不同颜色时,或是两个相同颜色中的一个,都要干掉

    实现见代码注释

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<vector>
     6 #include<cmath>
     7 using namespace std;
     8 inline int read()
     9 {
    10     int f=1,x=0;char ch=getchar();
    11     while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    12     while(ch<='9'&&ch>='0'){x=(x<<3)+(x<<1)+ch-'0';ch=getchar();}
    13     return f*x;
    14 }
    15 const int maxn=140000;
    16 int mx,n,k,a[maxn+100],issqr[2*maxn+100],cnt,ans[maxn+100],v[maxn+100],fa[2*maxn+100];
    17 int find(int x)
    18 {
    19     if(fa[x]!=x)fa[x]=find(fa[x]);
    20     return fa[x];
    21 }
    22 int jud(int x,int y)//x y have had conflict  &&判断是否能在两边
    23 {
    24     int x1=find(x),x2=find(x+maxn);//x1 x的敌人代表元素  x2  朋友
    25     int y1=find(y),y2=find(y+maxn);
    26     if(x1==y1||x2==y2)return 0;//have same friend or emery
    27     fa[x1]=y2,fa[x2]=y1;// divide into two different jihe
    28     return 1;    
    29 }
    30 void solve1()
    31 {
    32     for(int i=1;i<=n;i++)mx=max(mx,a[i]);
    33     ans[cnt]=n;
    34     for(int i=n;i>=1;i--)
    35     {
    36         for(int j=sqrt(a[i]);j*j<=mx+a[i];j++)
    37         {
    38             if(j*j-a[i]>0&&v[j*j-a[i]])
    39             {
    40                 for(int k=i+1;k<=ans[cnt];k++)v[a[k]]=0;
    41                 ans[++cnt]=i;
    42                 break;
    43             }
    44        }
    45        v[a[i]]=1;
    46     }
    47 }
    48 int vis[maxn],svis[maxn];
    49 void solve2()
    50 {
    51     for(int i=1;i<=2*maxn;i++)fa[i]=i;
    52     for(int i=1;i*i<=2*maxn;i++) issqr[i*i]=1;
    53     for(int i=n,j=n;i>=1;)
    54     {
    55         for(;j>=1;j--)
    56         {
    57             if(vis[a[j]])//如果这个点出现过一次
    58             {
    59                 if(!issqr[2*a[j]])continue;//并且这个点与自己同颜色的矛盾
    60                 if(svis[a[j]])goto fail;//如果这个点已经出现了两次,两个可以分到二分图的两边,所以不可能就再有了,成为断点
    61                 for(int k=1;k*k<=mx+a[j];k++)//所以这是第二个点
    62                     if(k*k-a[j]>0&&vis[k*k-a[j]]&&k*k!=2*a[j])goto fail;//找到了另一个与该颜色矛盾,跳过成为断点
    63                 svis[a[j]]=1;//这种颜色出现了两次,并且在二分图两边(1)
    64             }
    65             else //没有出现过
    66             {
    67                 for(int k=1;k*k<=mx+a[j];k++)
    68                     if(k*k-a[j]>0&&vis[k*k-a[j]])//找到了与它矛盾的点
    69                         if(svis[k*k-a[j]]||jud(a[j],k*k-a[j])==0)//如果这个点已经在二分图的两边(1情况)  或 这两个点不能放在两边
    70                             {fa[a[j]]=a[j];fa[a[j]+maxn]=a[j]+maxn;goto fail;}//清空这个断点的并查集信息
    71                 vis[a[j]]=1;
    72             }
    73         }
    74         fail:
    75         if(j==0)break;
    76         ans[++cnt]=j;
    77         for(;i>j;i--)fa[a[i]]=a[i],fa[a[i]+maxn]=a[i]+maxn,vis[a[i]]=svis[a[i]]=0;
    78     }
    79 }
    80 int main()
    81 {
    82     n=read(),k=read();
    83     for(int i=1;i<=n;i++)
    84         a[i]=read(),mx=max(mx,a[i]);
    85     if(k==1)solve1();
    86     else solve2();
    87     printf("%d
    ",cnt+1);
    88     for(int i=cnt;i>=1;i--) printf("%d ",ans[i]);
    89     puts("");
    90 }
    91 /*
    92 g++ 1.cpp -o 1
    93 ./1
    94 
    95 */
    View Code
    愿你在迷茫时,记起自己的珍贵。
  • 相关阅读:
    python模块
    Django基础
    Python __str__(self)和__unicode__(self)
    Redis基本操作
    测试面试宝典
    h5页面的测试方式
    selenium IDE的使用流程
    如何安装chrome扩展程序--selenium IDE
    Selenium 中 强制等待、显示等待、隐式等待的区别
    Selenium+Python 自动化 之八种元素定位方法
  • 原文地址:https://www.cnblogs.com/casun547/p/11295672.html
Copyright © 2011-2022 走看看