zoukankan      html  css  js  c++  java
  • 2017-4-13校内训练

    坑题+SB数据结构训练赛

    A.题目大意:某个地方有五个城市,给出十条单向边的长度,分别为1~2,1~3,2~3,2~4,3~4,3~5,4~5,4~1,5~1,5~2,问从一号城开始走,走长度恰好为n,走的城市数最少且字典序最小的方案。(1<=边长<=n<=500,000)

    思路:以在第i个城市走了长度为j为状态做bfs,字典序小的先拓展,复杂度O(15n)。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    inline int read()
    {
        int x;char c;
        while((c=getchar())<'0'||c>'9');
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=x*10+c-'0';
        return x;
    }
    #define MN 500000
    int d[5][2],u[5][MN+5],rx[5][MN+5],ry[5][MN+5],qx[5*MN+5],qy[5*MN+5],qn;
    void out(int x,int y)
    {
        if(y)out(rx[x][y],ry[x][y]);
        printf("%d ",x+1);
    }
    int main()
    {
        int n=read(),i,x,y,xx,yy,a,b;
        for(i=0;i<5;++i)d[i][0]=read(),d[i][1]=read();
        for(i=0;i<=qn;++i)
        {
            x=qx[i];y=qy[i];
            if(y==n){out(x,y);return 0;}
            a=1;b=2;if((x+a)%5>(x+b)%5)swap(a,b);
            xx=(x+a)%5;yy=y+d[x][a-1];
            if(yy<=n&&!u[xx][yy])++qn,u[qx[qn]=xx][qy[qn]=yy]=1,rx[xx][yy]=x,ry[xx][yy]=y;
            xx=(x+b)%5;yy=y+d[x][b-1];
            if(yy<=n&&!u[xx][yy])++qn,u[qx[qn]=xx][qy[qn]=yy]=1,rx[xx][yy]=x,ry[xx][yy]=y;
        }
        puts("-1");
    }

    B.题目大意:给出一个长度为n的序列,问有多少子串的乘积为完全平方数。(n<=500,000,数字大小<=10^6)

    思路:分解质因数后各质因子个数均为偶数即为完全平方数,那么同种质因子每有一个就异或上一个1,各种质因子异或出的数都为0即为完全平方数,按这个思路求一个前缀异或和,两个相同的前缀异或和即对应一个乘积为完全平方数的子串,hash一下上map就没了,复杂度O(nlogn)。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #include<map>
    using namespace std;
    #define ll long long
    inline int read()
    {
        int x;char c;
        while((c=getchar())<'0'||c>'9');
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=x*10+c-'0';
        return x;
    }
    #define MX 1000000
    map<ll,int> mp[3];
    const int magic[3]={31,37,233};
    ll f[3][MX+5],ff[3];
    int u[MX+5],uu[MX+5],p[MX+5],pn;
    void push(int x)
    {
        if(uu[x]^=1)for(int i=0;i<3;++i)ff[i]+=f[i][x];
        else for(int i=0;i<3;++i)ff[i]-=f[i][x];
    }
    int main()
    {
        int n=read(),i,j;ll ans=0;
        for(i=2;i<=MX;++i)
        {
            if(!u[i])p[++pn]=i,u[i]=i;
            for(j=1;i*p[j]<=MX;++j){u[i*p[j]]=p[j];if(i%p[j]==0)break;}
        }
        for(i=0;i<3;++i)for(f[i][0]=j=1;j<=MX;++j)f[i][j]=f[i][j-1]*magic[i];
        for(i=0;i<3;++i)++mp[i][0];
        while(n--)
        {
            for(i=read();i>1;i/=u[i])push(u[i]);
            for(i=0,j=MX;i<3;++i)j=min(j,mp[i][ff[i]]++);
            ans+=j;
        }
        cout<<ans;
    }

    C.题目大意:一个n*m的棋盘,一个棋子一开始在(i,j),每次若在(x,y)能移动到(x-a,y-b),(x+a,y-b),(x-a,y+b),(x+a,y+b)中的一格,问至少几步能移动到(1,1),(1,m),(n,1),(n,m)中的其中一格。(n,m<=10^6)

    思路:x,y坐标相互独立,可以先分别求出两种坐标的最小步数,如果一个先到就让另一个反复横跳,注意特判各种无解情况,复杂度O(1)。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define INF 1000000000
    int n,m,ans=INF,a,b;
    void cal(int x,int y,int tx,int ty)
    {
        if((tx-x)%a||(ty-y)%b)return;
        int px=(tx-x)/a,py=(ty-y)/b;
        if(px<0)px=-px;if(py<0)py=-py;
        if((px-py)%2)return;
        if(px==py){ans=min(ans,px);return;}
        if(px<py&&x-a<1&&x+a>n)return;
        if(py<px&&y-b<1&&y+b>m)return;
        ans=min(ans,max(px,py));
    }
    int main()
    {
        int i,j;
        scanf("%d%d%d%d%d%d",&n,&m,&i,&j,&a,&b);
        cal(i,j,1,1);cal(i,j,1,m);
        cal(i,j,n,1);cal(i,j,n,m);
        printf(ans<INF?"%d":"Poor Inna and pony!",ans);
    }

    D.题目大意:一个长度为n的小写字母串,支持两种操作:1.将一个子串的所有字母在字母表上循环后移k位(例如a后移2位是c,z后移两位是b);2.查询一个子串内有多少子序列可以通过重组得到一个回文串。(n,操作数<=10^5)

    思路:直接用线段树维护区间内各字母出现次数,每次O(26)更新信息,查询时先查出区间内各字母出现次数,枚举一个出现奇数次的字母或全是偶数次的,f1[i]表示i个字母中选出奇数个的方案,f2[i]表示i个字母中选出偶数个的方案,则f1[0]=0,f2[0]=1,每多一个字母我们都可以选或不选,则f1[i]=f2[i]=f1[i-1]+f2[i-1](i>0)(事实上都是2的次幂),然后很容易即可统计答案,复杂度O(26nlogn)。

    #include<cstdio>
    inline int read()
    {
        int x;char c;
        while((c=getchar())<'0'||c>'9');
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=x*10+c-'0';
        return x;
    }
    #define MN 100000
    #define L (k<<1)
    #define R (k<<1|1)
    #define MOD 1000000007
    struct node{int l,r,s[26],mk;}t[MN*4+5];
    int cnt[26],f1[MN+5],f2[MN+5],lf[26],rf[26];
    char s[MN+5];
    inline void up(int k){for(int i=0;i<26;++i)t[k].s[i]=t[L].s[i]+t[R].s[i];}
    inline void mark(int k,int x)
    {
        int i,j,s[26];
        for(i=0;i<26;++i)s[i]=t[k].s[i];
        for(i=0,j=x;i<26;++i,++j>25?j=0:0)t[k].s[j]=s[i];
        if((t[k].mk+=x)>25)t[k].mk-=26;
    }
    inline void down(int k){if(t[k].mk)mark(L,t[k].mk),mark(R,t[k].mk),t[k].mk=0;}
    void build(int k,int l,int r)
    {
        if((t[k].l=l)==(t[k].r=r)){++t[k].s[s[l]-'a'];return;}
        int mid=l+r>>1;
        build(L,l,mid);build(R,mid+1,r);up(k);
    }
    void add(int k,int l,int r,int x)
    {
        if(t[k].l==l&&t[k].r==r){mark(k,x%26);return;}
        int mid=t[k].l+t[k].r>>1;down(k);
        if(r<=mid)add(L,l,r,x);
        else if(l>mid)add(R,l,r,x);
        else add(L,l,mid,x),add(R,mid+1,r,x);
        up(k);
    }
    void query(int k,int l,int r)
    {
        if(t[k].l==l&&t[k].r==r){for(int i=0;i<26;++i)cnt[i]+=t[k].s[i];return;}
        int mid=t[k].l+t[k].r>>1;down(k);
        if(r<=mid)query(L,l,r);
        else if(l>mid)query(R,l,r);
        else query(L,l,mid),query(R,mid+1,r);
    }
    int main()
    {
        int n=read(),m=read(),t,l,r,i,ans;
        for(f2[0]=i=1;i<=n;++i)f1[i]=(f1[i-1]+f2[i-1])%MOD,f2[i]=(f1[i-1]+f2[i-1])%MOD;
        scanf("%s",s+1);
        build(1,1,n);
        while(m--)
        {
            t=read();l=read()+1;r=read()+1;
            if(t==1)add(1,l,r,read());
            else
            {
                for(i=0;i<26;++i)cnt[i]=0;query(1,l,r);
                for(i=0;i<26;++i)lf[i]=1LL*(i?lf[i-1]:1)*f2[cnt[i]]%MOD;
                for(i=26;i--;)rf[i]=1LL*(i<25?rf[i+1]:1)*f2[cnt[i]]%MOD;
                for(ans=rf[0]-1,i=0;i<26;++i)
                    ans=(ans+1LL*(i?lf[i-1]:1)*(i<25?rf[i+1]:1)%MOD*f1[cnt[i]])%MOD;
                printf("%d
    ",ans);
            }
        }
    }

    E.题目大意:询问[a,b]内有多少个数字是k的倍数。(1<=k<=10^18,-10^18<=a<=b<=10^18)

    思路:相信是个人都会做,乱写写呗,懒得判各种情况就写了奇怪的代码。

    #include<cstdio>
    #include<iostream>
    using namespace std;
    int main()
    {
        long long k,a,b,da,db,i;
        cin>>k>>a>>b;
        da=(a/k-5)*k;
        while(da<a)da+=k;
        db=(b/k+5)*k;
        while(db>b)db-=k;
        cout<<(db-da)/k+1;
    }

    F.题目大意:给出一棵n个节点的有根树,要求支持将一棵子树内所有点的权值加上V+d*K(其中d为该点到子树根的距离)和查询一条链上的权值和。(n<=10^5)

    思路:树剖一下,线段树多维护一个子树深度和,然后就能维护了,复杂度O(nlogn^2)。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    inline int read()
    {
        int x;char c;
        while((c=getchar())<'0'||c>'9');
        for(x=c-'0';(c=getchar())>='0'&&c<='9';)x=x*10+c-'0';
        return x;
    }
    #define MN 100000
    #define L (k<<1)
    #define R (k<<1|1)
    #define MOD 1000000007
    struct node{int l,r,s,ds,mk1,mk2;}t[MN*4+5];
    struct edge{int nx,t;}e[MN*2+5];
    int h[MN+5],en,fa[MN+5],d[MN+5],a[MN+5],s[MN+5],mx[MN+5],f[MN+5],dl[MN+5],dr[MN+5],cnt;
    inline void ins(int x,int y)
    {
        e[++en]=(edge){h[x],y};h[x]=en;
        e[++en]=(edge){h[y],x};h[y]=en;
    }
    void pre(int x)
    {
        s[x]=1;
        for(int i=h[x];i;i=e[i].nx)if(e[i].t!=fa[x])
        {
            fa[e[i].t]=x;d[e[i].t]=d[x]+1;
            pre(e[i].t);
            s[x]+=s[e[i].t];if(s[e[i].t]>s[mx[x]])mx[x]=e[i].t;
        }
    }
    void dfs(int x,int k)
    {
        a[dl[x]=++cnt]=d[x];f[x]=k;
        if(mx[x])dfs(mx[x],k);
        for(int i=h[x];i;i=e[i].nx)
            if(e[i].t!=mx[x]&&e[i].t!=fa[x])dfs(e[i].t,e[i].t);
        dr[x]=cnt;
    }
    inline void up(int k){t[k].s=(t[L].s+t[R].s)%MOD;}
    inline void mark(int k,int x1,int x2)
    {
        t[k].s=(t[k].s+1LL*x1*(t[k].r-t[k].l+1)+1LL*x2*t[k].ds)%MOD;
        t[k].mk1=(t[k].mk1+x1)%MOD;
        t[k].mk2=(t[k].mk2+x2)%MOD;
    }
    inline void down(int k)
    {
        mark(L,t[k].mk1,t[k].mk2);mark(R,t[k].mk1,t[k].mk2);
        t[k].mk1=t[k].mk2=0;
    }
    void build(int k,int l,int r)
    {
        if((t[k].l=l)==(t[k].r=r)){t[k].ds=a[l];return;}
        int mid=l+r>>1;
        build(L,l,mid);build(R,mid+1,r);
        up(k);t[k].ds=(t[L].ds+t[R].ds)%MOD;
    }
    void add(int k,int l,int r,int x1,int x2)
    {
        if(t[k].l==l&&t[k].r==r){mark(k,x1,x2);return;}
        int mid=t[k].l+t[k].r>>1;down(k);
        if(r<=mid)add(L,l,r,x1,x2);
        else if(l>mid)add(R,l,r,x1,x2);
        else add(L,l,mid,x1,x2),add(R,mid+1,r,x1,x2);
        up(k);
    }
    int query(int k,int l,int r)
    {
        if(t[k].l==l&&t[k].r==r)return t[k].s;
        int mid=t[k].l+t[k].r>>1;down(k);
        if(r<=mid)return query(L,l,r);
        if(l>mid)return query(R,l,r);
        return (query(L,l,mid)+query(R,mid+1,r))%MOD;
    }
    int query(int x,int y)
    {
        int res=0;
        for(;f[x]!=f[y];x=fa[f[x]])
        {
            if(d[f[x]]<d[f[y]])swap(x,y);
            res=(res+query(1,dl[f[x]],dl[x]))%MOD;
        }
        if(dl[x]>dl[y])swap(x,y);
        return ((res+query(1,dl[x],dl[y]))%MOD+MOD)%MOD;
    }
    int main()
    {
        int n,m,rt,i,x,y,z;char o[5];
        n=read();m=read();rt=read();
        for(i=1;i<n;++i)ins(read(),read());
        pre(rt);dfs(rt,rt);
        build(1,1,n);
        while(m--)
        {
            scanf("%s",o);x=read();y=read();
            if(o[0]=='U')z=read(),add(1,dl[x],dr[x],(y-1LL*d[x]*z)%MOD,z);
            else printf("%d
    ",query(x,y));
        }
    }
  • 相关阅读:
    Python函数式编程:内置函数map()使用说明
    Python 内置函数 range的使用
    Python的局部变量和全局变量
    Python 数据处理扩展包: pandas 模块的DataFrame介绍(读写数据库的操作)
    Python 数据处理扩展包: pandas 模块的DataFrame介绍(创建和基本操作)
    python模块 mysql-python安装(在ubuntu系统下)
    Python 数据处理扩展包: numpy 和 pandas 模块介绍
    HTML 5 Web Storage 使用
    CRM的组织架构
    WEB UI做TREE
  • 原文地址:https://www.cnblogs.com/ditoly/p/20170413C.html
Copyright © 2011-2022 走看看