2017-3-3校内训练

Posted ditoly

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\n",(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]);
}

 

以上是关于2017-3-3校内训练的主要内容,如果未能解决你的问题,请参考以下文章

校内训练2019-11-15跳一跳

校内训练2019-11-15逮虾户

校内训练2019-11-15表演

20171129校内训练

「csp校内训练 2019-10-30」解题报告

三中校内训练净化