• 2017-3-3校内训练


    hzwer出丧题虐人啦 ACM赛制 4/7

    A.恼人的青蛙

    题目大意:给定N*M矩阵上K个点,定义一条合法路径为从矩形外一点沿一条直线穿过矩形,每次走相同长度且在矩形内每步都要踩在给定点上,问经过给定点最多的路径经过几个点(若小于3输出0)(N,M,K<=5000)。

    思路:把点按横坐标第一关键字纵坐标第二关键字排序,f[i][j]表示有一条到i的路径,i上一个点是j,此时路径经过点数,每次确定i,j后就可以根据i,j算出j再前一个点的坐标,直接转移,复杂度O(K^2)。评测机极慢稍微卡卡常才能过。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define MN 5000
    struct P{int x,y;}p[MN+5];
    bool cmp(P a,P b){return a.x==b.x?a.y<b.y:a.x<b.x;}
    short g[MN+5][MN+5],f[MN+5][MN+5];
    int n,m,k,i,j,x,y,ans=0;
    inline int G(int x,int y){return x>0&&x<=n&&y>0&&y<=m?g[x][y]:-1;}
    inline int cal(int a,int b){return (a<<1)-b;}
    int main()
    {
        scanf("%d%d%d",&n,&m,&k);
        for(i=1;i<=k;++i)scanf("%d%d",&p[i].x,&p[i].y);
        sort(p+1,p+k+1,cmp);
        for(i=1;i<=k;++i)
        {
            g[p[i].x][p[i].y]=i;
            for(j=1;j<i;++j)
            {
                x=G(cal(p[j].x,p[i].x),cal(p[j].y,p[i].y));
                f[i][j]=x?x<0?2:f[j][x]+1:-k;
                if(G(cal(p[i].x,p[j].x),cal(p[i].y,p[j].y))<0&&f[i][j]>ans)ans=f[i][j];
            }
        }
        printf("%d",ans<3?0:ans);
    }

    C.本原串

    题目大意:求所有长度为N的01串中有多少个不存在小于N的循环节(循环节长度应能整除N),答案对2008取模(N<=100,000,000)。

    思路:长度为N的01串有2^N个,考虑去掉有循环节的,先O(N^0.5)求出N的所有因数,排序,对所有小于N的因数记si=-1表示以该因数为循环节的01串个数对答案贡献的倍数。从大往小计算,遇到第i个因数ai,答案加上si*2^ai,由于可能被重复统计,对每个i再向前找到第j个因数满足j<i且aj整除ai,sj-=si,ai的所有因数必然都被n的所有因数包含,这样即可不重不漏的统计。复杂度不好计算,总之很靠谱,O(能过)。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    #define MOD 2008
    int pw(int y)
    {
        int r=1,t=2;
        for(;y;y>>=1,t=t*t%MOD)if(y&1)r=r*t%MOD;
        return r;
    }
    #define MN 20000
    int n,z[MN+5],zn,s[MN+5];
    int main()
    {
        int i,j,ans;
        while(~scanf("%d",&n))
        {
            for(zn=0,i=1;i*i<n;++i)if(n%i==0)z[++zn]=i,z[++zn]=n/i;
            if(i*i==n)z[++zn]=i;
            sort(z+1,z+zn+1);
            for(ans=pw(n),i=1;i<zn;++i)s[i]=-1;
            for(i=zn;--i;)
            {
                ans=(ans+s[i]*pw(z[i]))%MOD;
                for(j=i;--j;)if(z[i]%z[j]==0)s[j]=(s[j]-s[i])%MOD;
            }
            printf("%d
    ",(ans+MOD)%MOD);
        }
    }

    D.Optimal Milking

    题目大意:K台机器,C头奶牛,每头奶牛对应一台机器,每台机器对应不超过M头奶牛,给出K+C个点的图,每个点表示一头奶牛或一台机器,要求最小化奶牛机器成功配对后奶牛到其配对机器路径长度的最大值,求出这个值。(K<=30,C<=200,M<=15)

    思路:二分答案,网络流check。

    #include<cstdio>
    #include<cstring>
    #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<<3)+(x<<1)+c-'0';
        return x;
    }
    #define MN 230
    #define ME 6230
    #define S MN+1
    #define T MN+2
    #define INF 0x3FFFFFFF
    struct edge{int nx,t,w;}e[ME*2+5];
    int h[MN+5],en,n,m,w,g[MN+5][MN+5];
    inline void ins(int x,int y,int w)
    {
        e[++en]=(edge){h[x],y,w};h[x]=en;
        e[++en]=(edge){h[y],x,0};h[y]=en;
    }
    int d[MN+5],q[MN+5],qn,c[MN+5];
    bool bfs()
    {
        int i,j;
        memset(d,0,sizeof(d));
        for(d[q[i=qn=0]=S]=1;i<=qn;++i)for(j=c[q[i]]=h[q[i]];j;j=e[j].nx)
            if(e[j].w&&!d[e[j].t])d[q[++qn]=e[j].t]=d[q[i]]+1;
        return d[T];
    }
    int dfs(int x,int r)
    {
        if(x==T)return r;
        int u=0,k;
        for(int&i=c[x];i;i=e[i].nx)if(e[i].w&&d[x]+1==d[e[i].t])
        {
            k=dfs(e[i].t,r-u<e[i].w?r-u:e[i].w);
            u+=k;e[i].w-=k;e[i^1].w+=k;
            if(u==r)return u;
        }
        return d[x]=0,u;
    }
    bool check(int x)
    {
        int i,j,ans=0;
        memset(h,0,sizeof(h));en=1;
        for(i=1;i<=n;++i)ins(S,i,w);
        for(i=1;i<=m;++i)ins(i+n,T,1);
        for(i=1;i<=n;++i)for(j=1;j<=m;++j)
            if(g[i][j+n]<=x)ins(i,j+n,1);
        while(bfs())ans+=dfs(S,INF);
        return ans==m;
    }
    int main()
    {
        int i,j,k,l,r,mid,ans;
        n=read();m=read();w=read();
        for(i=1;i<=n+m;++i)for(j=1;j<=n+m;++j)
        {
            g[i][j]=read();
            if(i!=j&&!g[i][j])g[i][j]=INF;
        }
        for(k=1;k<=n+m;++k)for(i=1;i<=n+m;++i)for(j=1;j<=n+m;++j)
            g[i][j]=min(g[i][j],g[i][k]+g[k][j]);
        for(l=0,r=INF;l<=r;)
            if(check(mid=l+r>>1))ans=mid,r=mid-1;
            else l=mid+1;
        printf("%d",ans);
    }

    E.King's Rout

    题目大意:1~N的数,M条限制关系,每条要求一个数必须在另一个的前面,求一个方案使得满足所有限制条件且1在最前面,1位置相同的情况下2在最前面,以此类推。(N<=200,000,M<=400,000)。

    思路:拓扑排序,可以发现反过来字典序最大即为题目中要求的方案,用堆维护即可。

    #include<cstdio>
    #include<queue>
    using namespace std;
    inline int read()
    {
        int x=0;char c;
        while((c=getchar())<'0'||c>'9');
        for(;c>='0'&&c<='9';c=getchar())x=(x<<3)+(x<<1)+c-'0';
        return x;
    }
    #define MN 200000
    #define MM 400000
    priority_queue<int> pq;
    struct edge{int nx,t;}e[MM+5];
    int h[MN+5],en,r[MN+5],ans[MN+5];
    inline void ins(int x,int y){e[++en]=(edge){h[x],y};h[x]=en;}
    int main()
    {
        int n,m,i,j;
        n=read();m=read();
        while(m--)++r[i=read()],ins(read(),i);
        for(i=1;i<=n;++i)if(!r[i])pq.push(i);
        for(i=n;i;--i)
        {
            ans[i]=pq.top();pq.pop();
            for(j=h[ans[i]];j;j=e[j].nx)if(!--r[e[j].t])pq.push(e[j].t);
        }
        for(i=1;i<=n;++i)printf("%d ",ans[i]);
    }

    G.弦图

    题目大意:给定一长为N的字符串,询问第K小子串,给一个参数T,若T=0则相同子串不重复计算,若T=1则相同子串重复计算。(N<=500,000)

    思路:后缀自动机模板题。

    #include<cstdio>
    #define MN 500000
    #define ND 1000000
    char st[MN+5];
    int f[ND+5],c[ND+5][26],d[ND+5],tn=1,p=1;
    int v[ND+5],s[ND+5],z[MN+5],q[ND+5];
    void ins(int x)
    {
        int np=++tn,q,nq,i;d[np]=d[p]+1;v[np]=1;
        for(;p&&!c[p][x];p=f[p])c[p][x]=np;
        if(!p)f[np]=1;
        else if(d[q=c[p][x]]==d[p]+1)f[np]=q;
        else
        {
            d[nq=++tn]=d[p]+1;f[nq]=f[q];f[q]=f[np]=nq;
            for(i=0;i<26;++i)c[nq][i]=c[q][i];
            for(;c[p][x]==q;p=f[p])c[p][x]=nq;
        }
        p=np;
    }
    void out(int x,int k)
    {
        if(k<=v[x])return;k-=v[x];
        for(int i=0;i<26;++i)
            if(k<=s[c[x][i]]){putchar(i+'a');out(c[x][i],k);return;}
            else k-=s[c[x][i]];
    }
    int main()
    {
        int t,k,i,j;
        scanf("%s%d%d",st,&t,&k);
        for(i=0;st[i];++i)ins(st[i]-'a');
        for(i=1;i<=tn;++i)++z[d[i]];
        for(i=MN;i--;)z[i]+=z[i+1];
        for(i=1;i<=tn;++i)q[z[d[i]]--]=i;
        if(t)for(i=1;i<=tn;--i)v[f[q[i]]]+=v[q[i]];
        else for(i=1;i<=tn;++i)v[i]=1;
        for(v[1]=0,i=2;i<=tn;++i)s[i]=v[i];
        for(i=1;i<=tn;++i)for(j=0;j<26;++j)s[q[i]]+=s[c[q[i]][j]];
        if(k>s[1])puts("-1");else out(1,k);
    }
  • 相关阅读:
    Java中的四种内部类
    用输入/输出写一个程序,让用户输入一些姓名和电话号码
    分批读取大数据问题
    Linux产生序列数字
    两个有序链表的合并
    int和Integer的区别
    wait()和sleep()的区别
    Unix和Windows文件格式转化
    截取字符串的代码实现
    查看系统信息
  • 原文地址:https://www.cnblogs.com/ditoly/p/20170303C.html
Copyright © 2020-2023  润新知