zoukankan      html  css  js  c++  java
  • [4.13校内训练赛]

    来自FallDream的博客,未经允许,请勿转载,谢谢。


    ditoly几分钟就AK了 跪下来了

    -----------------------------

    A.有1到5 5个点,每个点到它的编号+1和+2都有单向边。给出边的长度,你要从1号点出发走恰好距离恰好为N的路,并求出经过的点最少的情况下字典序最小的方案。n<=500000

    题解:倒过来DP一下,然后直接走呗。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define INF 200000000
    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 b[7][500005];
    int n,to[5][2]={{3,4},{4,0},{0,1},{1,2},{2,3}},d[5][2],ans=INF,from=-1;
    
    void dfs(int x,int dd)
    {
        printf("%d ",x+1);
        if(dd==n) return;
        for(int i=0;i<5;i++)
            for(int k=0;k<2;k++)
            if(to[i][k]==x&&dd+d[i][k]<=n&&b[i][dd+d[i][k]]==b[x][dd]-1)
            {
                dfs(i,dd+d[i][k]);
                return;
            }
    }
    
    int main()
    {
        n=read();
        d[1][1]=read();d[2][0]=read();
        d[2][1]=read();d[3][0]=read();
        d[3][1]=read();d[4][0]=read();
        d[4][1]=read();d[0][0]=read();
        d[0][1]=read();d[1][0]=read();
        memset(b,64,sizeof(b));
        for(int i=0;i<5;i++) b[i][n]=0;
        for(int i=n;i;i--)
            for(int j=0;j<5;j++) 
                for(int k=0;k<2;k++)
                    if(i-d[j][k]>=0)
                        b[to[j][k]][i-d[j][k]]=min(b[to[j][k]][i-d[j][k]],b[j][i]+1); 
        if(b[0][0]>=INF) return 0*puts("-1");
        else dfs(0,0); 
        return 0;
    }

    B.给定n个数ai,求满足积是完全平方数的子串的个数。n<=500000 ai<=1000000
    题解:先分解质因数,然后求出每个的前缀异或和,发现前缀异或和都相同的才会计入答案,所以可以哈希一下,给每个质数对应一个哈希值,每次异或上质数的哈希值就行了。

    #include<iostream>
    #include<cstdio>
    #define ll long long
    #define MX 1000000
    #define orz 2333333
    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,s[MX+5],a[MX],num=0,nn[MX+5];ll p[MX+5],p2[MX+5],X=1e10,Y=1e11,ans=0;
    bool b[MX+5];
    int head[orz],cnt=0;
    struct my_map{int ans,next;ll x,y;}e[MX+5];
    
    
    void ins(ll x,ll y)
    {
        int j=x%orz;
        for(int i=head[j];i;i=e[i].next)
            if(e[i].x==x&&e[i].y==y) 
            {
                ans+=e[i].ans;++e[i].ans;
                return;
            }
        e[++cnt]=(my_map){1,head[j],x,y};head[j]=cnt;
    }
    
    int Ran()
    {
        static unsigned int x=88956;
        x^=(x<<13);x^=(x>>17);x^=(x<<5);
        return x;
    }
    
    int main()
    {
        n=read();for(int i=1;i<=n;i++) a[i]=read();
        for(int i=2;i<=MX;i++)
        {
            if(!b[i]) s[++num]=i,p[i]=Ran()*Ran()%ditoly,p2[i]=Ran()*Ran()%ditoly;
            for(int j=1;s[j]*i<=MX&&j<=num;j++)
                b[s[j]*i]=1;
        }
        ins(X,Y);
        for(int i=1;i<=n;i++)
        {
            int j=a[i];
            for(int k=1;j>1&&s[k]<=1000;k++)
                while(j%s[k]==0) j/=s[k],X^=p[s[k]],Y^=p2[s[k]];
            if(j>1) X^=p[j],Y^=p2[j];
            ins(X,Y);
        }
        cout<<ans<<endl;
        return 0;
    }

    C.给定一个n*m的棋盘,你在(x,y),要走到棋盘的任意一个角。每次移动,你只能让横坐标变化a,纵坐标变化b,且不能到棋盘外,求最小的变化次数。
    题解:大判断。

    #include<iostream>
    #include<cstdio>
    #define INF 2000000000
    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 ans=INF,n,m,x,y,a,b;
    
    int calc(int xx,int yy)
    {
        if((xx&1)!=(yy&1)) return INF;
        if(xx>yy&&y+b>m&&y-b<=0) return INF;
        if(yy>xx&&x+a>n&&x-a<=0) return INF;
        return max(xx,yy);
    }
    
    int main()
    {
        n=read();m=read();x=read();y=read();a=read();b=read();
        if((x-1)%a==0&&(y-1)%b==0) ans=min(ans,calc((x-1)/a,(y-1)/b)); 
        if((x-1)%a==0&&(m-y)%b==0) ans=min(ans,calc((x-1)/a,(m-y)/b));
        if((n-x)%a==0&&(y-1)%b==0) ans=min(ans,calc((n-x)/a,(y-1)/b));
        if((n-x)%a==0&&(m-y)%b==0) ans=min(ans,calc((n-x)/a,(m-y)/b));
        if(ans<INF) printf("%d
    ",ans);
        else puts("Poor Inna and pony!");
        return 0;
    }

    D.给定一个由小写字母(长度<=100000)组成的字符串,支持两个操作 1)让一段字符后移t位  后移一位是指 a->b b->c z->a

    2) 求一段字符有多少个子集可以组成完全平方数。      

    题解:考虑线段树维护字符串每种字符的出现次数,然后每次询问找出次数之后排列组合算答案。复杂度$O(26nlogn)$

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define MN 100000
    #define ll long long
    #define mod 1000000007
    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,q,qu[50],p[MN+5];
    char st[MN+5];
    
    struct data
    {
        int c[26];
        data(){}
        data(int x){memset(c,0,sizeof(c));c[x]=1;}
        data operator+(const data&b)
        {
            data x;
            for(register int i=0;i<26;i++) x.c[i]=c[i]+b.c[i]; 
            return x;
        } 
        void change(int x)
        {
            for(register int i=0;i<26;i++) qu[(i+x)%26]=c[i];
            for(register int i=0;i<26;i++) c[i]=qu[i];
        }
    };
    struct Tree{int l,r,val;data x;}T[MN*4+5];
    
    void pushdown(int x)
    {
        int l=x<<1,r=x<<1|1;
        T[l].x.change(T[x].val);
        T[r].x.change(T[x].val);
        T[l].val=(T[l].val+T[x].val)%26;;
        T[r].val=(T[r].val+T[x].val)%26;
        T[x].val=0;
    }
    
    void build(int x,int l,int r)
    {
        if((T[x].l=l)==(T[x].r=r)) {T[x].x=data(st[l]-'a');return;}
        int mid=l+r>>1;
        build(x<<1,l,mid);build(x<<1|1,mid+1,r);
        T[x].x=T[x<<1].x+T[x<<1|1].x;
    }
    
    void renew(int x,int l,int r,int t)
    {
        if(T[x].l==l&&T[x].r==r){T[x].x.change(t);T[x].val=(T[x].val+t)%26;return;}
        if(T[x].val) pushdown(x);
        int mid=T[x].l+T[x].r>>1;
        if(r<=mid) renew(x<<1,l,r,t);
        else if(l>mid) renew(x<<1|1,l,r,t);
        else renew(x<<1,l,mid,t),renew(x<<1|1,mid+1,r,t);
        T[x].x=T[x<<1].x+T[x<<1|1].x;
    }
    
    data query(int x,int l,int r)
    {
        if(T[x].l==l&&T[x].r==r) return T[x].x;
        if(T[x].val) pushdown(x);
        int mid=T[x].l+T[x].r>>1;
        if(r<=mid)return query(x<<1,l,r);
        else if(l>mid)return query(x<<1|1,l,r);
        else return query(x<<1,l,mid)+query(x<<1|1,mid+1,r); 
    }
    
    int pow(int x,int k)
    {
        int sum=1;
        for(int i=x;k;k>>=1,i=1LL*i*i%mod)
            if(k&1) sum=1LL*sum*i%mod;
        return sum;
    }
    
    int main()
    {
        n=read();q=read();
        for(int i=1;i<=n;i++) p[i]=pow(2,i-1);
        scanf("%s",st+1);build(1,1,n);
        for(int i=1;i<=q;i++)
        {
            int op=read(),l=read()+1,r=read()+1;
            if(op==1) {int x=read()%26;if(x) renew(1,l,r,x);}
            else
            {
                data ans=query(1,l,r);int pa=1,sum=0;
                for(int i=0;i<26;i++)if(ans.c[i]) pa=1LL*pa*p[ans.c[i]]%mod;
                for(int i=0;i<26;i++) if(ans.c[i])
                        sum=(sum+1LL*pow(2,ans.c[i]-1)*pa%mod*pow(p[ans.c[i]],mod-2)%mod)%mod;
                sum=(sum+pa)%mod;
                printf("%d
    ",sum-1);
            }
        }
        return 0;
    }

    E.......   求[a,b]里面有多少个数能被k整除。  a,b,k<=10^18
    题解:.......瞎搞

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll long long
    #define LL (ll)5e18
    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;
    }
    
    ll k,a,b;
    
    int main()
    {
        k=read();a=read();b=read();a+=LL/k*k;b+=LL/k*k;
        ll bg=(a+k-1)/k,ed=b/k;
        printf("%lld
    ",ed-bg+1);
        return 0;
    }

    F.一棵树,要求支持两种操作。 n<=100000 m<=100000 1)让一棵子树的所有点加上v+kd vk给定,d表示那个点和子树的根的深度差。

    2)询问一条链上的权值和

    有链操作和子树操作,考虑树剖。第一个操作我们可以通过线段树上打标记实现,所以这道题就做完啦。复杂度$O(nlog^{2}n)$

    #include<iostream>
    #include<cstdio>
    #define mod 1000000007
    #define Mod 10000000070000000LL
    #define INF 2000000000
    #define MN 100000
    #define ll long long
    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,rt,mx[MN+5],size[MN+5],head[MN+5],cnt=0,nl[MN+5],nr[MN+5],top[MN+5],fa[MN+5],dep[MN+5],dn=0,p[MN+5];
    struct edge{int to,next;}e[MN*2+5];
    struct TREE{int l,r;ll val,tag,x,d;}T[MN*4+5];
    inline void ins(int f,int t)
    {
        e[++cnt]=(edge){t,head[f]};head[f]=cnt;
        e[++cnt]=(edge){f,head[t]};head[t]=cnt;
    }
    
    void dfs1(int x,int f)
    {
        fa[x]=f;size[x]=1;mx[x]=0;
        for(int i=head[x];i;i=e[i].next)
            if(e[i].to!=f)
            {
                dep[e[i].to]=dep[x]+1;
                dfs1(e[i].to,x);
                size[x]+=size[e[i].to];
                if(size[e[i].to]>size[mx[x]]) mx[x]=e[i].to;
            }
    }
    
    void dfs2(int x,int tp)
    {
        top[x]=tp;nl[x]=++dn;p[dn]=x;
        if(mx[x]) dfs2(mx[x],tp);
        for(int i=head[x];i;i=e[i].next)
            if(e[i].to!=fa[x]&&e[i].to!=mx[x])
                dfs2(e[i].to,e[i].to);
        nr[x]=dn;
    }
    
    void pushdown(int x)
    {
        int l=x<<1,r=x<<1|1;
        if(T[x].tag)
        {
            T[l].tag=(T[l].tag+T[x].tag)%mod;
            T[r].tag=(T[r].tag+T[x].tag)%mod;
            T[l].x=(T[l].x+1LL*(T[l].r-T[l].l+1)*T[x].tag)%mod; 
            T[r].x=(T[r].x+1LL*(T[r].r-T[r].l+1)*T[x].tag)%mod;
            T[x].tag=0;
        }
        if(T[x].val)
        {
            T[l].val=(T[l].val+T[x].val)%mod;
            T[r].val=(T[r].val+T[x].val)%mod;
            T[l].x=(T[l].x+1LL*T[l].d*T[x].val+Mod)%mod;
            T[r].x=(T[r].x+1LL*T[r].d*T[x].val+Mod)%mod;
            T[x].val=0;
        }
    }
    
    void build(int x,int l,int r)
    {
        if((T[x].l=l)==(T[x].r=r)){T[x].d=dep[p[l]];return;}
        int mid=l+r>>1;
        build(x<<1,l,mid);build(x<<1|1,mid+1,r);
        T[x].d=(T[x<<1].d+T[x<<1|1].d)%mod;
    }
    
    void Renew(int x,int l,int r,int ad)
    {
        if(T[x].l==l&&T[x].r==r)
        {
            T[x].tag=(T[x].tag+ad)%mod;
            T[x].x=(T[x].x+1LL*(r-l+1)*ad)%mod;
            return;
        }
        if(T[x].val||T[x].tag) pushdown(x);
        int mid=T[x].l+T[x].r>>1;
        if(r<=mid) Renew(x<<1,l,r,ad);
        else if(l>mid) Renew(x<<1|1,l,r,ad);
        else Renew(x<<1,l,mid,ad),Renew(x<<1|1,mid+1,r,ad);
        T[x].x=(T[x<<1].x+T[x<<1|1].x)%mod;
    } 
    
    void renew(int x,int l,int r,int ad)
    {
        if(T[x].l==l&&T[x].r==r)
        {
            T[x].val=(T[x].val+ad+Mod)%mod;
            T[x].x=(T[x].x+1LL*T[x].d*ad+Mod)%mod;
            return;
        }
        if(T[x].val||T[x].tag) pushdown(x);
        int mid=T[x].l+T[x].r>>1;
        if(r<=mid) renew(x<<1,l,r,ad);
        else if(l>mid) renew(x<<1|1,l,r,ad);
        else renew(x<<1,l,mid,ad),renew(x<<1|1,mid+1,r,ad);
        T[x].x=(T[x<<1].x+T[x<<1|1].x)%mod;
    }
    
    ll query(int x,int l,int r)
    {
        if(T[x].l==l&&T[x].r==r) return T[x].x;
        if(T[x].val||T[x].tag) pushdown(x);
        int mid=T[x].l+T[x].r>>1;
        if(r<=mid) return query(x<<1,l,r);
        else if(l>mid) return query(x<<1|1,l,r);
        else return (query(x<<1,l,mid)+query(x<<1|1,mid+1,r))%mod;
    }
    
    int Solve(int x,int y)
    {
        ll sum=0;
        while(top[x]!=top[y])
        {
            if(dep[top[x]]<dep[top[y]]) swap(x,y);
            sum=(sum+query(1,nl[top[x]],nl[x]))%mod;
            x=fa[top[x]];
        }
        if(nl[x]>nl[y]) swap(x,y);
        sum=(sum+query(1,nl[x],nl[y]))%mod;
        return sum;
    }
    
    char op[5];
    int main()
    {
        n=read();m=read();rt=read();
        for(int i=1;i<n;i++) ins(read(),read());
        dep[rt]=1;dfs1(rt,0);dfs2(rt,rt);
        build(1,1,n);
        for(int i=1;i<=m;i++)
        {
            scanf("%s",op+1);
            if(op[1]=='U')
            {
                int t=read(),v=read(),k=read();
                Renew(1,nl[t],nr[t],(v-1LL*k*dep[t]+Mod)%mod);
                renew(1,nl[t],nr[t],k);
            }
            else
            {
                int x=read(),y=read();
                printf("%d
    ",Solve(x,y));
            }
        }
        return 0;
    }


     

  • 相关阅读:
    03_线性表
    02_算法与数据结构
    01_python中内置类型的时间复杂度
    00_常见的时间复杂度
    03_docker导出和导入镜像
    09_创建mysql数据库的用户
    14_linux添加主机列表
    13_linux修改主机名
    12_centos7安装好后的网络设置
    00_使用pdb调试python代码
  • 原文地址:https://www.cnblogs.com/FallDream/p/xunlian413.html
Copyright © 2011-2022 走看看