20190803考试反思

  这次考试就不骂自己了,毕竟骂了也没用。T1是水题。。用map手卡30分,我tm。。。。然后以为这就结束了,然后去改T2,T2WA40,我写的主席树但是修改是自己yy的,以为就是错了,然后把离散化去了,WA80?????!!!然后加上WA40。。。。然后我好好研究了一下,突然想到它可能询问从没出现过的颜色,然后判了一句,A了。。。。因为没出现过就是0,主席树查不出来。。。T3考场上吃屎一会再说。

  T1:这是一道规律题,找的话其实打个父亲表,看一下就能知道,一个数的父亲就是这个数之前减去离他最近的斐波数,我们又可以知道这个斐波数增长飞快,见过通项的都知道,这玩意是指数级的,所以就可以打个表知道大概60多个就到13位了,找父亲log60,抬lca是60,一次操作就是常数,m次绝对可以接受,结果忘了之前搞得一个map没删,就死了30分。

  

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<map>
using namespace std;
long long f[10000];    
long long rd()
{
    long long s=0,w=1;
    char cc=getchar();
    while(cc<'0'||cc>'9') {if(cc=='-') w=-1;cc=getchar();}
    while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar();
    return s*w;
}
long long fa(long long x)
{
    long long id=lower_bound(f+1,f+64,x)-f-1;
    return x-f[id];
}
long long getdep(long long tmp)
{
    long long ans=0,x=tmp;
    while(x!=1)
    {
        ++ans;
        x=fa(x);
    }
    return ans;
}
long long lca(long long a,long long b)
{
    int depa=getdep(a),depb=getdep(b);
    if(depa<depb) swap(a,b),swap(depa,depb);
    while(depa>depb) a=fa(a),depa--;
    if(a==b) return a;
    while(fa(a)!=fa(b)) a=fa(a),b=fa(b);
    return fa(a);
}
int main()
{
    f[0]=1;f[1]=1;
    for(int i=2;i<=63;i++)
    {
        f[i]=f[i-1]+f[i-2];
    }
    int m=rd();
    for(int i=1;i<=m;i++)
    {
        long long a=rd(),b=rd();
        if(a==1||b==1)
        {
            puts("1");
            continue;
        }
        printf("%lld\n",lca(a,b));
    }
    return 0;
}
/*
g++ 1.cpp -o 1
./1
5
1 1
2 3
5 7
7 13
4 12
*/
View Code

  T2:手动修改的主席树,因为这个修改不是修改,是交换,这很重要,那这样后面的主席树都不用改,只改一颗就行了,然后就可以性感询问,在线回复了。还是一样,可持久化烧内存,内存开够就没了。主席树码量极小

  

#include<iostream>
#include<cstdio>
using namespace std;
const int N=300050;
int rt[N],a[N],p[N],tt=0,cnt=0;
struct tree{int lc,rc,w;}tr[50000020];
int rd()
{
    int s=0,w=1;
    char cc=getchar();
    while(cc<'0'||cc>'9') {if(cc=='-') w=-1;cc=getchar();}
    while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar();
    return s*w;
}
void insert(int &x,int l,int r,int p,int va)
{
    tr[++tt]=tr[x];x=tt;
    if(l==r)
    {
        tr[x].w+=va;
        return;
    }
    int mid=(l+r)>>1;
    if(p<=mid) insert(tr[x].lc,l,mid,p,va);
    else insert(tr[x].rc,mid+1,r,p,va);
}
int query(int x,int l,int r,int p)
{
    if(l==r)return tr[x].w;
    int mid=(l+r)>>1;
    if(p<=mid)return query(tr[x].lc,l,mid,p);
    else return query(tr[x].rc,mid+1,r,p);
}
int main()
{
    int n=rd(),m=rd();
    for(int i=1;i<=n;i++)
    {
        a[i]=rd();
        if(!p[a[i]]) p[a[i]]=++cnt;
    }
    for(int i=1;i<=n;i++)
    {
        rt[i]=rt[i-1];
        insert(rt[i],1,cnt,p[a[i]],1);
    }
    while(m--)
    {
        int op=rd();
        if(op==1)
        {
            int l=rd(),r=rd(),c=rd();
            if(!p[c]) puts("0");
            else printf("%d\n",query(rt[r],1,cnt,p[c])-query(rt[l-1],1,cnt,p[c]));
        }
        else 
        {
            int l=rd();
            insert(rt[l],1,cnt,p[a[l]],-1);
            insert(rt[l],1,cnt,p[a[l+1]],1);
            swap(a[l],a[l+1]);
        }
    }
}
/*
g++ 2.cpp -o 2
./2
10 9
1 2 3 4 5 6 1 2 3 4
1 1 3 3
1 4 6 3
2 3
1 1 3 3
1 4 6 3
1 1 10 4
1 1 10 3
1 1 10 2
1 1 10 1
*/
View Code

  T3:首先这个题不是DP,倒着扫一遍,贪心找最长的合法区间,然后既能保证最少,也能保证最小。然后k=1的时候好搞,随便搞搞就行了,k=2的时候用二分图来做,我考试的时候鬼畜没看到k只能等于1或2,然后就开始yy,发现如果在一张图上如果把非敌对关系建图(反图)的话,在只有双联通分量里的点才能分成一个小组,于是我就开始了愉快的tarjan。。。。这题k=2的时候二分图可以跑过,我们就可以通过二分图判定,来判断这一堆猫啊不兔子是否能分两组,这个题的打法没怎么见过,不是dp只能瞎打。自己yy了一个调了一下午。

  另外:亲测告诉各位卡常大师,sqrt函数我估计是$O(2^{n})$的,慢到没分数,直接打表比sqrt快3000ms

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
//const int L=1<<20|1;
//char buffer[L],*S,*T;
//#define getchar() ((S==T&&(T=(S=buffer)+fread(buffer,1,L,stdin),S==T))?EOF:*S++)
using namespace std;
const int N=3000050;
bool v[N],ch[N];
int c[N],s[N],a[N],tt,qn,tot,fr[N*2];
struct node{int fr,to,pr;}mo[N*2];
void add(int x,int y)
{
    mo[++tt].fr=x;
    mo[tt].to=y;
    mo[tt].pr=fr[x];
    fr[x]=tt;
}
bool dfs(const register int x,const register int cl)
{
    c[x]=cl;
    //cout<<x<<endl;
    for(int i=fr[x];i;i=mo[i].pr)
    {
        const register int to=mo[i].to;
        //cout<<to<<" "<<cl<<endl;
        if(c[to]==cl)return false;
        if(c[to]==0&&!dfs(to,-cl))return false;
    }
    return true;
}
int rd()
{
    int s=0,w=1;
    char cc=getchar();
    while(cc<'0'||cc>'9') {if(cc=='-') w=-1;cc=getchar();}
    while(cc>='0'&&cc<='9') s=(s<<3)+(s<<1)+cc-'0',cc=getchar();
    return s*w;
}
int main()
{
    int bm=0;
    int n=rd(),K=rd();
    for(int i=1;i<=512;i++) ch[i*i]=1;
    for(int i=1;i<=n;i++)
        a[i]=rd(),bm=max(bm,a[i]);
    if(K==1)
    {
        for(int i=n;i;)
        {
            bool flag=1;
            int j=i;
            for(;j;j--)
            {
                for(int k=1;k<=512;k++)
                {
                    if(v[k*k-a[j]]){flag=0;break;}
                }
                if(flag==0) break;
                v[a[j]]=1;
            }
            for(int k=j;k<=i;k++) v[a[k]]=0;
            i=j;
            if(j!=0) s[++tot]=j;
        }
        printf("%d\n",tot+1);
        for(int i=tot;i;i--) printf("%d ",s[i]);
        puts("");
        return 0;
    }
    else
    {
        for(int i=n;i;)
        {
            bool flag=1;
            register int j=i;
            for(;j;j--)
            {
                for(int k=j+1;k<=i;k++)if(ch[a[j]+a[k]])add(j,k),add(k,j);
                for(int k=j;k<=i;k++)c[k]=0;
                if(!dfs(j,1))break;
            }
            for(int k=j;k<=i;k++)fr[k]=0;
            i=j;tt=0;
            s[++tot]=j;
        }
        printf("%d\n",tot);
        for(int i=tot-1;i;i--) printf("%d ",s[i]);
        puts("");
        return 0;
    }
}
/*
g++ 3.cpp -o 3
./3
5 2
1 3 15 10 6
*/
View Code

 

 

posted @ 2019-08-03 21:16  starsing  阅读(172)  评论(2编辑  收藏  举报