• [3.9校内训练赛]


    不要纠结为什么3.9的比赛比3.10的还迟做完,你们首先得知道这场是ditoly出的

    ditoly丧病出题人啊丧病出题人啊丧病出题人啊

    本机上 T1 std3.000s卡过,我的3.1s被卡了 T3 总共2s,std写的treap跑的飞快,我写的替罪羊2.1s也被卡了 

    听说学校机子T1只要2s,学校机子真神奇,MBA还是不适合跑程序,低压i5伤不起啊......

    分割线------------------------------------

    A.一个n*m的网格图,每个格子都有一个0-9的权值,求(1,1)到(n,m)的最短路径。n,m<=5000,数据随机生成。

    不会做,交了个spfa上去只有50,一个学弟写的dij过了70,真的牛逼。

    题解:把每个权值大于0的点拆成很多个权值为1的点,然后bfs,遇到0的点就往外先扩展。由于数据随机生成,复杂度期望为4.5*nm

    发现直接用stl的队列和手写队列差了大概0.2s,反正本机就是跑不过去,假装已经在学校机子上A了。

    #include<iostream>
    #include<cstdio>
    #define INF 2000000000
    #define MX 15000000
    using namespace std;
    inline int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    
    int n,m,xx,yy,nowx,nowy,top=0,tail=0;
    char s[5005][5005];
    int d[5005][5005];
    bool b[5005][5005];
    short qx[MX+5],qy[MX+5];
    const int dis[4][2]={{1,0},{-1,0},{0,1},{0,-1}};
    
    void solve(int x,int y)
    {
        for(int i=0;i<4;i++)
        {
            xx=x+dis[i][0];
            yy=y+dis[i][1];
            if(b[xx][yy])continue;
            b[xx][yy]=1;d[xx][yy]=d[x][y]+s[xx][yy]-'0';
            if(s[xx][yy]=='0')solve(xx,yy);
            else qx[++top>MX?(top-=MX):top]=xx,qy[top]=yy;
        }
    }
    
    int main()
    {
        freopen("secret.in","r",stdin);
        freopen("secret.out","w",stdout);
        n=read();m=read();
        for(int i=1;i<=n;i++)
            scanf("%s",s[i]+1);
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
                d[i][j]=INF;
        d[1][1]=s[1][1]-'0';
        qx[++top]=1;qy[top]=1;b[1][1]=1;
        for(int i=0;i<=max(n,m);i++)
            b[i][0]=b[0][i]=b[n+1][i]=b[i][m+1]=1;
        while(top!=tail&&d[n][m]==INF)
        {
            nowx=qx[++tail>MX?(tail-=MX):tail];nowy=qy[tail];
            if(s[nowx][nowy]>'0') --s[nowx][nowy];
            if(s[nowx][nowy]=='0') solve(nowx,nowy);
            else qx[++top>MX?(top-=MX):top]=nowx,qy[top]=nowy;
        }
        printf("%d
    ",d[n][m]);
        return 0;
    }

    T2.k组询问,每次给定n,求∑f(i)/i  2<=i<=n,其中f(i)表示i能够分为多少种完全k次方数。 保留8位小数,差值不超过10-8判对, n<=10^36 k<=100000

    std做法:用pq对10^12暴力,这时候答案0.9999998几,然后发现答案不会超过1,剩下的打表。

    我的做法: 枚举次数(最多50),然后暴力枚举底数直到结果超过10^15,这时候已经0.99999997,打表最后几个数。我以为是输出答案相差不超过10-8,就输出0.99999999,结果是正确答案和你的输出答案不超过10-8,被坑了,100000组询问错了几十组,真的难受。实际上再二分一下就能过了,但我懒,也不想改了。

    我的复杂度是  MAXN=10^15  log*(MAXN^0.5+MAXN^0.33+...+MAXN^0.02) log是快速幂的小log,复杂度非常科学,但就输在了打表上。

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #define MAXN 1000000000000000LL
    #define ll long long
    using namespace std;
    inline ll read()
    {
        ll x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
     
    double ad[100005];
    double ts[100005];
    double ans[100005];
    char st[50];
    const int lim[51]={0,0,31622776,100000,5623,1000,316,138,74,46,31,23,17,14,11,10,8,7,6,6,5,5,4,4,4,3,3,3,3,3,3,3,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2};
    int t;
    ll sum;
     
    ll pow(int x,ll p)
    {
        ll sum=1;
        for(ll i=x;p;p>>=1,i*=i)if(p&1) sum*=i;
        return sum;
    }
     
    struct node{
        ll x;int num;
    }s[100005];
     
    bool cmp(node x,node y){return x.x<y.x;}
     
    int main()
    {
        t=read();
        for(int i=1;i<=t;i++)
        {
            scanf("%s",st+1);int len=strlen(st+1);
            if(len>18) s[i].x=MAXN,ad[i]=0.00000003;
            else
            {   for(int j=1;st[j];j++) s[i].x=s[i].x*10+st[j]-'0';
                if(s[i].x>=23333333333333333LL)ad[i]=0.00000003;
                else if(s[i].x>=4501216504303236LL) ad[i]=0.00000002;
                else if(s[i].x>=1603210729132996LL) ad[i]=0.00000001;
            };
            s[i].num=i;
        }
        sort(s+1,s+t+1,cmp);
        for(int l=2;l<50;++l)
        {
            memset(ts,0,sizeof(ts));
            for(int i=2,j=1;i<=lim[l]&&j<=t;i++)
            {
                sum=pow(i,l);
                for(;s[j].x<sum&&j<=t;++j);
                if(j<=t) ts[j]+=(double)1/sum;
            }
            for(int i=1;i<=t;i++)
                ans[i]+=(ts[i]=ts[i-1]+ts[i]);
        }
        for(int i=1;i<=t;i++) ad[s[i].num]+=ans[i];
        for(int i=1;i<=t;i++) printf("%0.8lf
    ",ad[i]);
        return 0;
    } 

    C.给定一个长度为n的数列,每个数都是1-n以内。m次询问,每次询问一个区间,再给定s和k个下标。如果区间内有一个数出现超过区间长度一半,答案是那个数,否则答案是s,然后把k个下标的位置的数字改成这次的答案。求每一次的答案和最后整个数列的答案。 n,m<=500000,∑k <=1000000

    有个学长用了随机化A了,结果被某个无良出题人临时搞数据卡了40.

    做法:如果只考虑一个区间求有没有出现那么多次的人,我们可以采用一个很经典的做法。先记下第一个数和此时的出现次数(一开始是1),然后一个个往后处理,如果这个数和现在几下的数不同,那么出现次数-1,否则出现次数+1。如果出现次数变为0,则把记下的数字改成现在这个数,这样一定能找到那个数。

    比如3 2 4 3 3    (3,1)->(2,0)->(4,1)->(3,0)->(3,1),找到了数字3

    我们发现这个操作满足区间加法,所以可以用线段树来维护,每次从区间中找到那个数字。

    可是如果没有出现次数大于一半的数字怎么办?很简单,我们可以用一棵平衡树来维护每个数字的出现位置,去里面查询一下就好啦。复杂度(n+k)logn

    常数大没有考虑splay,就写了替罪羊,讲道理也不慢,但是就是在本机被卡了。std写的treap跑的飞快,有空学学。

    #include<iostream>
    #include<cstdio>
    #define MAXN 1500000
    #define N 524288
    using namespace std;
    int read()
    {
        int x=0,f=1;char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9'){x=x*10+ch-'0'; ch=getchar();}
        return x*f;
    }
    
    bool b[MAXN+5];
    int fa[MAXN+5],size[MAXN+5],c[MAXN+5][2],nn[MAXN+5],q[MAXN+5],s[MAXN+5],col[MAXN+5];
    int rt[500005],mark=0,n,m,top,cnt=0;
    struct data{
        int x,num;
        data operator+(data y){if(!num)return y;if(!y.num)return *this;if(x==y.x)return(data){x,num+y.num};
            if(num>y.num)return (data){x,num-y.num};return(data){y.x,y.num-num};}
    }T[N*2+5];
    
    void renew(int x,int ad)
    {
        T[x+=N].x=ad;
        for(x>>=1;x;x>>=1) T[x]=T[x<<1]+T[x<<1|1];
    }
    
    data query(int l,int r)
    {
        data sum=(data){0,0};
        for(l+=N-1,r+=N+1;l^r^1;l>>=1,r>>=1)
        {
            if(~l&1)sum=sum+T[l+1];
            if( r&1)sum=sum+T[r-1];
        }
        return sum;
    }
    
    void init(){for(int i=N;i;i--)T[i]=T[i<<1]+T[i<<1|1];}
    
    void ins(int&x,int rk,int last)
    {
        //cout<<"ins"<<x<<" "<<rk<<" "<<last<<endl;
        if(!x){x=++cnt;size[x]=1;nn[x]=rk;fa[x]=last;b[x]=1;col[x]=s[rk];return;}
        if(rk<=nn[x])ins(c[x][0],rk,x);else ins(c[x][1],rk,x);
        size[x]=size[c[x][0]]+size[c[x][1]]+b[x];
        if(max(size[c[x][0]],size[c[x][1]])>0.7*size[x]) mark=x;
    }
    
    void dfs(int x)
    {
        if(c[x][0])dfs(c[x][0]);
        if(b[x])q[++top]=x;
        if(c[x][1])dfs(c[x][1]);
    }
    
    void build(int&x,int l,int r,int last)
    {
        if(l>r)return;int mid=(l+r)>>1;x=q[mid];fa[x]=last;
        build(c[x][0],l,mid-1,x);build(c[x][1],mid+1,r,x);
        size[x]=size[c[x][0]]+size[c[x][1]]+b[x];
    }
    
    void rebuild(int x)
    {
        top=mark=0;dfs(x);int y=fa[x];
        for(int i=1;i<=top;i++)fa[q[i]]=c[q[i]][0]=c[q[i]][1]=0;
        if(!y)build(rt[col[x]],1,top,0);
        else build(c[y][c[y][1]==x],1,top,y);
    }
    
    void del(int x,int k)
    {
        // cout<<"del"<<x<<" "<<k<<endl;
        if(nn[x]==k&&b[x]){b[x]=0;size[x]--;return;}
        if(k<=nn[x])del(c[x][0],k);else del(c[x][1],k);
        size[x]=size[c[x][0]]+size[c[x][1]]+b[x];
    }
    
    int query2(int x,int r)
    {
        //cout<<"query2"<<x<<" "<<r<<" "<<nn[x]<<endl;
        if(!x)return 0;
        if(nn[x]>r)return query2(c[x][0],r);
        else return size[c[x][0]]+b[x]+query2(c[x][1],r);
    }
    
    void solve(int l,int r,int q,int k)
    {
        data xx=query(l,r);if(xx.num&&query2(rt[xx.x],r)-query2(rt[xx.x],l-1)>=(r-l+3)/2) q=xx.x;
        // cout<<xx.x<<" "<<query2(rt[xx.x],r)-query2(rt[xx.x],l-1)<<"!!"<<endl;
        printf("%d
    ",q);
        for(int j=1;j<=k;j++)
        {int x=read();if(s[x]!=q){renew(x,q);del(rt[s[x]],x);s[x]=q;ins(rt[q],x,0);if(mark)rebuild(mark);}}
    }
    
    int main()
    {
        //freopen("president.in","r",stdin);
        //freopen("president.out","w",stdout);
        n=read();m=read();
        for(int i=1;i<=n;i++)
        {s[i]=read();T[i+N]=(data){s[i],1};ins(rt[s[i]],i,0);if(mark)rebuild(mark);}init();
        while(m--){int l=read(),r=read(),q=read(),k=read();solve(l,r,q,k);}
        solve(1,n,-1,0);
        return 0;
    }

    丧病出题人丧病出题人!!!!!!!!!!!

  • 相关阅读:
    js通过class获取元素时的兼容性解决方案
    html5的八大特性
    typeof与instanceof的区别
    evel()与JSON.parset()的区别
    apt-get出现的问题
    Linux下开启计划任务日志
    ls
    win10自带IE上不了网的解决办法
    crontab -e文件存放路径
    Linux系统下面crontab选择默认编译器
  • 原文地址:https://www.cnblogs.com/FallDream/p/ditoly39.html
Copyright © 2020-2023  润新知