zoukankan      html  css  js  c++  java
  • Codeforces Round #483 (Div. 1) 简要题解

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


    为了证明一下我又来更新了,写一篇简要的题解吧。

    这场比赛好像有点神奇,E题莫名是道原题,导致有很多选手直接过掉了(Claris 表演24s过题)。然而D题比E题要难一些,分还少。


    A. Finite or not?

    先把(frac{p}{q})约成最简分数,然后就是要判断是否(q)的所有质因数都是(b)的质因数。

    每次取(g=gcd(b,q)),并尽可能的让(q)(g),最后判断(q)是否是1即可。

    还有一种思路,就是求(b^{64} mod q),判断这个值是否为0,但是乘法是大整数之间进行的,所以稍微有点复杂。

    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    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;
    }
    inline ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
    int main()
    {
    	for(int T=read();T;--T)
    	{
    		ll p=read(),q=read(),b=read();
    		ll g=gcd(p,q),c;p/=g;q/=g;
    		while((g=gcd(q,b))>1)
    			do q/=g; while(q%g==0);	
    		puts(q>1?"Infinite":"Finite");
    	}
    	return 0;
    }
    
    #include<bits/stdc++.h>
    using namespace std;
    #define ll long long
    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;
    }
    inline ll gcd(ll x,ll y){return y?gcd(y,x%y):x;}
    inline ll mul(ll x,ll mod){return ((x*x-(ll)((long double)x*x/mod)*mod)%mod+mod)%mod;}
    int main()
    {
    	for(int T=read();T;--T)
    	{
    		ll p=read(),q=read(),b=read();
    		q/=gcd(p,q);b%=q;
    		for(int i=1;i<=6&&b;++i) b=mul(b,q);
    		puts(b?"Infinite":"Finite");
    	}
    	return 0;
    }
    

    B. XOR-pyramid

    没什么好说的,令f[i][j]表示区间([i,j])得到的结果,(f[i][j]=f[i][j-1] xor f[i+1][j])

    然后求一个区间最大值即可。

    #include<bits/stdc++.h>
    #define MN 5000
    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 f[MN+5][MN+5],n,Q,mx[MN+5][MN+5];
    int main()
    {
    	n=read();
    	for(int i=1;i<=n;++i) f[i][i]=mx[i][i]=read();
    	for(int i=n;i;--i) for(int j=i+1;j<=n;++j)
    		f[i][j]=f[i][j-1]^f[i+1][j],mx[i][j]=max(f[i][j],max(mx[i+1][j],mx[i][j-1]));
    	for(int Q=read(),l,r;Q--;) l=read(),r=read(),printf("%d
    ",mx[l][r]);
    	return 0;
    }
    

    C. Elevator

    先搜出所有电梯上人的状态,总共只有不到720种,然后再记一下前几个人已经进了电梯,现在在几楼,状态树不超过720*2000*9,转移数量(O(1)),bfs即可。

    #include<bits/stdc++.h>
    #define MN 2000
    #define MX 720
    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=1e9,n,a[MN+5],b[MN+5],cnt,num[MX+5],A[6],c[MX+5][5];
    int id[10][10][10][10],f[15000005],q[15000005],top;
    void dfs(int x,int v)
    {
    	++cnt;num[cnt]=x-1;id[A[1]][A[2]][A[3]][A[4]]=cnt;
    	for(int j=1;j<x;++j) c[cnt][j]=A[j];
    	if(x>4)return;
    	for(int i=v;i<=9;++i) A[x]=i,dfs(x+1,i);
    	A[x]=0;
    }
    inline int ID(int x,int y,int z){return x*MX*10+y*10+z;}
    void Try(int x,int y,int z,int v)
    {
    	int d=ID(x,y,z);
    	if(v<f[d]) f[q[++top]=d]=v;	
    }
    int main()
    {
    	dfs(1,1);memset(f,40,sizeof(f));
    	n=read();
    	for(int i=1;i<=n;++i) a[i]=read(),b[i]=read();
    	f[q[top=1]=ID(0,id[0][0][0][0],1)]=0;
    	for(int i=1;i<=top;++i)
    	{
    		int x=q[i]/MX/10,y=(q[i]/10)%MX,z=q[i]%10,v=f[q[i]];
    		if(z<9) Try(x,y,z+1,v+1);
    		if(z>1) Try(x,y,z-1,v+1);
    		int nn=0;
    		for(int j=1;j<=num[y];++j)
    			if(c[y][j]!=z) A[++nn]=c[y][j];
    		for(int j=nn+1;j<=4;++j) A[j]=0;
    		Try(x,id[A[1]][A[2]][A[3]][A[4]],z,v+(num[y]-nn));
    		if(x<n&&a[x+1]==z&&num[y]<4)
    		{
    			int nn=0,k=1;
    			for(;k<=num[y];++k)
    				if(c[y][k]<=b[x+1]) A[++nn]=c[y][k];
    				else break;
    			A[++nn]=b[x+1];
    			for(;k<=num[y];++k) A[++nn]=c[y][k];
    			while(nn<4) A[++nn]=0;
    			Try(x+1,id[A[1]][A[2]][A[3]][A[4]],z,v+1); 
    		}
    	}
    	for(int i=1;i<=9;++i) ans=min(ans,f[ID(n,id[0][0][0][0],i)]);
    	cout<<ans;
    	return 0;
    }
    

    D. Arkady and Rectangles

    这个题有点意思。。。

    首先讲讲我自己想的一个做法吧。

    考虑对(x)建线段树,在每个节点上维护y的颜色段,对于每个矩形,将它插入到线段树上对应节点上。

    然后考虑每一个颜色段是否能被看到,必须满足线段树上它的父亲中没有将它完全盖掉,并且两个儿子也不都盖掉它。类似线段树分治的思想,可以按照分治层数可持久化一下,维护一棵线段树支持区间取max,区间最小值,这样就可以处理父亲的影响了。对于儿子的,考虑现在正在计算点(x)上的某一个颜色段是否满足,那么枚举左右儿子中每一段与这个段相交的段,假设左右儿子中的最小值满足条件,那么儿子也不会产生影响。

    处理好影响之后,可以将这个点的颜色段和儿子的段合并,记下每段最小值。

    这个做法是(O(nlog^{2}n))的,空间可以利用线段树分治时版本很少的性质做到(O(nlogn)),听起来常数就很大,实际上更大,加一些优化可以卡过去。

    然后有比较简单的做法,考虑对横坐标扫描线,维护一棵关于y的线段树。对于每个矩形,依旧插入到对应的y坐标节点,然后我们求出每个点代表的区间能看到的矩形的最大值,这个信息不难用set维护。

    每次操作后,我们考虑线段树根节点能看到什么矩形,暴力记下它之后,将它标记为已经看到。对于已经看到的矩形,除了在合并区间信息时稍有不同以外,没有太大区别,每个矩形只会被看到1次。

    这个做法是时空级别一样但是显然会更小,常数也小得多,可以轻松跑过去。

    不过这个做法cf上好像挺多人写的,我就不写了(跑

    贴一个我的sb做法。

    #pragma GCC optimize("Ofast")
    #pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,tune=native")
    #include<bits/stdc++.h>
    #define MN 100000
    #define G() st[x].lower_bound((Li){L,0,0})
    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;
    }
    struct Rec{int x1,y1,x2,y2;}s[MN+5];
    int n,Lx[MN*2+5],Ly[MN*2+5],numx,numy,ans,vis[MN+5],B,C,cnt,rt[55];
    struct Li{int l,r,v;}a[MN+5],b[MN+5],c[MN+5];
    struct Tree{int l,r,mx,x;short d;}T[4000005];
    struct cmp{bool operator()(const Li&a,const Li&b){return a.l==b.l?(a.r==b.r?a.v<b.v:a.r<b.r):a.l<b.l;}};
    set<Li,cmp> st[524295];set<Li,cmp>::iterator it;
    void Ins(int x,int lt,int rt,int l,int r,int L,int R,int now)
    {
        if(l==lt&&r==rt)
        {
            it=G();
            if(it!=st[x].begin())
            {
                --it;Li y=*it;
                if(it->r>R)
                {
                    st[x].erase(it);
                    st[x].insert((Li){y.l,L-1,y.v});
                    st[x].insert((Li){R+1,y.r,y.v});
                }
                else if(it->r>=L)
                {
                    st[x].erase(it);
                    st[x].insert((Li){y.l,L-1,y.v});
                }
            }
            for(it=G();it->l<=R;it=G())
            {
                Li y=*it;st[x].erase(it);
                if(y.r>R) st[x].insert((Li){R+1,y.r,y.v});
            }
            st[x].insert((Li){L,R,now});
            return;
        }
        int mid=lt+rt>>1;
        if(r<=mid) Ins(x<<1,lt,mid,l,r,L,R,now);
        else if(l>mid) Ins(x<<1|1,mid+1,rt,l,r,L,R,now);
        else Ins(x<<1,lt,mid,l,mid,L,R,now),Ins(x<<1|1,mid+1,rt,mid+1,r,L,R,now);
    }
    void Build(int x,int l,int r)
    {
        if(st[x].insert((Li){1,numy,0}),l==r) return;
        int mid=l+r>>1;
        Build(x<<1,l,mid);Build(x<<1|1,mid+1,r);
    }
    int now_dep;
    inline int newnode(int x){return T[x].d==now_dep?x:(T[++cnt]=T[x],T[cnt].d=now_dep,cnt);}
    inline void update(int x){T[x].mx=max(T[x].x,min(T[T[x].l].mx,T[T[x].r].mx));}
    void Modify(int x,int lt,int rt,int l,int r,int v)
    {
        if(lt==l&&rt==r){T[x].x=max(T[x].x,v);T[x].mx=max(T[x].mx,v);return;}
        int mid=lt+rt>>1;
        if(r<=mid) Modify(T[x].l=newnode(T[x].l),lt,mid,l,r,v);
        else if(l>mid) Modify(T[x].r=newnode(T[x].r),mid+1,rt,l,r,v);
        else Modify(T[x].l=newnode(T[x].l),lt,mid,l,mid,v),
             Modify(T[x].r=newnode(T[x].r),mid+1,rt,mid+1,r,v);
        update(x);
    }
    int Query(int x,int lt,int rt,int l,int r)
    {
        if(!x) return 0;
        if(lt==l&&rt==r) return T[x].mx;
        int mid=lt+rt>>1;
        if(r<=mid) return max(Query(T[x].l,lt,mid,l,r),T[x].x);
        else if(l>mid) return max(Query(T[x].r,mid+1,rt,l,r),T[x].x);
        else return max(T[x].x,min(Query(T[x].l,lt,mid,l,mid),Query(T[x].r,mid+1,rt,mid+1,r)));
    }
    void Solve(int x,int l,int r,int dep)
    {
        if(l==r)
        {
            for(it=st[x].begin();it!=st[x].end();++it)
                if(Query(rt[dep-1],1,numy,it->l,it->r)<=it->v)
                    if(!vis[it->v]) vis[it->v]=1,++ans;
            return;
        }
        now_dep=dep;
        int mid=l+r>>1,A=0,L=x<<1,R=L|1,precnt=cnt;
        rt[dep]=newnode(rt[dep-1]);
        for(it=st[x].begin();it!=st[x].end();++it) Modify(rt[dep],1,numy,it->l,it->r,it->v);
        Solve(L,l,mid,dep+1);Solve(R,mid+1,r,dep+1);B=C=0;
        for(it=st[x].begin();it!=st[x].end();++it) a[++A]=*it;
        st[x].clear();
        for(it=st[L].begin();it!=st[L].end();++it) b[++B]=*it;st[L].clear();
        for(it=st[R].begin();it!=st[R].end();++it) c[++C]=*it;st[R].clear();
        for(int i=1,j=1,k=1;i<=A;++i)
        {
            int ok=0;
            while(j<=B&&b[j].r<a[i].l) ++j;
            while(k<=C&&c[k].r<a[i].l) ++k;
            while(j>1&&b[j-1].r>=a[i].l) --j;
            while(k>1&&c[k-1].r>=a[i].l) --k;
            for(int last=a[i].l-1;!ok&&last<a[i].r;)
            {
            	int v=min(b[j].v,c[k].v),rr=min(b[j].r,c[k].r);
    			if(v<=a[i].v&&Query(rt[dep],1,numy,last+1,min(rr,a[i].r))<=a[i].v) ok=1;
    			last=rr;
    			if(b[j].r==rr) ++j;
    			if(c[k].r==rr) ++k;
            }
            if(ok&&!vis[a[i].v]) vis[a[i].v]=1,++ans;
        }
        if(x==1) return;
        for(int i=1,j=1,k=1,last=0;i<=A;)
        {
            int v=max(a[i].v,min(b[j].v,c[k].v)),rr=min(a[i].r,min(b[j].r,c[k].r));
            st[x].insert((Li){last+1,rr,v});last=rr;
            if(a[i].r==rr) ++i;
            if(b[j].r==rr) ++j;
            if(c[k].r==rr) ++k;
        }
        cnt=precnt;
    }
    int main()
    {
        n=read();
        for(int i=1;i<=n;++i)
        {
            s[i].x1=read();s[i].y1=read();
            s[i].x2=read();s[i].y2=read();
            Lx[++numx]=s[i].x1;Lx[++numx]=s[i].x2;
            Ly[++numy]=s[i].y1;Ly[++numy]=s[i].y2;
        }
        sort(Lx+1,Lx+numx+1);numx=unique(Lx+1,Lx+numx+1)-Lx-1;
        sort(Ly+1,Ly+numy+1);numy=unique(Ly+1,Ly+numy+1)-Ly-1;
        Build(1,1,numx);
        for(int i=1;i<=n;++i)
        {
            s[i].x1=lower_bound(Lx+1,Lx+numx+1,s[i].x1)-Lx;
            s[i].x2=lower_bound(Lx+1,Lx+numx+1,s[i].x2)-Lx-1;
            s[i].y1=lower_bound(Ly+1,Ly+numy+1,s[i].y1)-Ly;
            s[i].y2=lower_bound(Ly+1,Ly+numy+1,s[i].y2)-Ly-1;
            Ins(1,1,numx,s[i].x1,s[i].x2,s[i].y1,s[i].y2,i);
        }
        Solve(1,1,numx,1);
        printf("%d
    ",ans);
        return 0;
    }
    

    E. NN country

    原题是bzoj2167,但是数据范围稍有加大。

    这道题以前还被拿出来联考了,当时就讨论过了一个log的做法。

    首先考虑最终的走法,肯定是先从两个点尽可能往lca上面跳,然后坐巴士绕过lca或者做两次,并在lca转车。

    先简单求出每个点走一步能走到的最小深度,然后通过倍增实现尽可能跳的这一步。

    接下来只需要判断有没有同时经过这两个点的线路了,这就是一个简单的二维数点问题。

    #include<bits/stdc++.h>
    #define MN 200000
    #define MD 18
    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;
    }
    vector<int> v[MN+5],V[MN+5];
    int n,m,Q,fa[MD+1][MN+5],f[MD+1][MN+5],dep[MN+5],rt[MN+5],dfn[MN+5],dn,p[MN+5],nr[MN+5],cnt;
    struct Tree{int l,r,x;}T[12000005];
    inline int lca(int x,int y)
    {
    	if(dep[x]<dep[y]) swap(x,y);
    	for(int k=dep[x]-dep[y],j=0;k;k>>=1,++j)
    		if(k&1) x=fa[j][x];
    	if(x==y)return x;
    	for(int i=MD;~i;--i) if(fa[i][x]!=fa[i][y]) x=fa[i][x],y=fa[i][y];
    	return fa[0][x];	
    }
    void dfs(int x)
    {
    	dfn[x]=++dn;p[dn]=x;
    	for(int i=0;i<v[x].size();++i) dfs(v[x][i]);
    	nr[x]=dn;
    }
    int Query(int x,int l,int r,int lt=1,int rt=n)
    {
    	if(!x||(l==lt&&r==rt))return T[x].x;	
    	int mid=lt+rt>>1;
    	if(r<=mid) return Query(T[x].l,l,r,lt,mid);
    	else if(l>mid) return Query(T[x].r,l,r,mid+1,rt);
    	else return Query(T[x].l,l,mid,lt,mid)+Query(T[x].r,mid+1,r,mid+1,rt);
    }
    inline int newnode(int x){T[++cnt]=T[x];return cnt;}
    void Modify(int x,int l,int r,int k)
    {
    	if(++T[x].x,l==r) return;
    	int mid=l+r>>1;
    	if(k<=mid) Modify(T[x].l=newnode(T[x].l),l,mid,k);
    	else Modify(T[x].r=newnode(T[x].r),mid+1,r,k);
    }
    inline int Min(int x,int y){return dep[x]<dep[y]?x:y;}
    int main()
    {
    	n=read();
    	for(int i=2;i<=n;++i) fa[0][i]=read(),dep[i]=dep[fa[0][i]]+1,v[fa[0][i]].push_back(i);
    	for(int i=1;i<=n;++i) f[0][i]=i;dfs(1);
    	for(int i=1;i<=MD;++i) for(int j=1;j<=n;++j) fa[i][j]=fa[i-1][fa[i-1][j]];
    	m=read();
    	for(int i=1;i<=m;++i)
    	{
    		int x=read(),y=read(),z=lca(x,y);
    		f[0][x]=Min(f[0][x],z);
    		f[0][y]=Min(f[0][y],z);
    		if(dfn[x]>dfn[y]) swap(x,y);
    		V[y].push_back(x);
    	}
    	for(int i=1;i<=n;++i)
    	{
    		rt[i]=newnode(rt[i-1]);
    		for(int j=0;j<V[p[i]].size();++j)
    			Modify(rt[i],1,n,dfn[V[p[i]][j]]);	
    	}
    	for(int i=n;i;--i) f[0][fa[0][i]]=Min(f[0][fa[0][i]],f[0][i]);
    	for(int i=1;i<=MD;++i) for(int j=1;j<=n;++j) f[i][j]=f[i-1][f[i-1][j]];
    	Q=read();
    	for(int i=1;i<=Q;++i)
    	{
    		int x=read(),y=read(),z=lca(x,y),ans=0;
    		for(int j=MD;~j;--j)
    		{
    			if(dep[f[j][x]]>dep[z]) ans+=1<<j,x=f[j][x];
    			if(dep[f[j][y]]>dep[z]) ans+=1<<j,y=f[j][y];
    		}
    		if(ans>n) {puts("-1");continue;}
    		if(x==z||y==z) {printf("%d
    ",ans+1);continue;}
    		if(dfn[x]>dfn[y]) swap(x,y); 
    		printf("%d
    ",ans+2-bool(Query(rt[nr[y]],dfn[x],nr[x])-Query(rt[dfn[y]-1],dfn[x],nr[x])));
    	}
    	return 0;
    }
    
  • 相关阅读:
    Go 语言简介(下)— 特性
    Array.length vs Array.prototype.length
    【转】javascript Object使用Array的方法
    【转】大话程序猿眼里的高并发架构
    【转】The magic behind array length property
    【转】Build Your own Simplified AngularJS in 200 Lines of JavaScript
    【转】在 2016 年做 PHP 开发是一种什么样的体验?(一)
    【转】大话程序猿眼里的高并发
    php通过token验证表单重复提交
    windows 杀进程软件
  • 原文地址:https://www.cnblogs.com/FallDream/p/cf483.html
Copyright © 2011-2022 走看看