• 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;
    }
    
  • 相关阅读:
    有关线程与进程的参考资料
    [Notes] 各种数据源配置
    [Notes] 显卡更新后docker nvidia-runtime不可用
    [Tips] numpy diff
    [Tips] vs code ssh remote情况下如何选者python
    RSA算法之学习
    湖南大学推荐书《社会学大纲》阅读有感 其一
    解决某些应用程序阻止了IDM集成到浏览器中的问题
    Oracle实现判断功能三种方式总结
    JS实现数字每三位加逗号
  • 原文地址:https://www.cnblogs.com/FallDream/p/cf483.html
Copyright © 2020-2023  润新知