• AtCoder Grand Contest 005题解


    传送门

    (A)

    咕咕

    const int N=5e5+5;
    char s[N];int res,n,sum;
    int main(){
    	scanf("%s",s+1),res=n=strlen(s+1);
    	fp(i,1,n)if(s[i]=='S')++sum;
    		else if(sum)--sum,res-=2;
    	printf("%d
    ",res);
    	return 0;
    }
    

    (B)

    咕咕

    //quming
    #include<bits/stdc++.h>
    #define R register
    #define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
    #define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
    #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
    template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
    template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
    using namespace std;
    typedef long long ll;
    const int N=2e5+5,inf=0x3f3f3f3f;
    int a[N],l[N],r[N],st[N],n,top;ll res;
    int main(){
    	scanf("%d",&n);
    	fp(i,1,n)scanf("%d",&a[i]);
    	a[0]=a[n+1]=0,st[++top]=0;
    	fp(i,1,n){
    		while(top&&a[i]<a[st[top]])--top;
    		l[i]=st[top],st[++top]=i;
    	}
    	st[top=1]=n+1;
    	fd(i,n,1){
    		while(top&&a[i]<a[st[top]])--top;
    		r[i]=st[top],st[++top]=i;
    	}
    	fp(i,1,n)res+=1ll*a[i]*(i-l[i])*(r[i]-i);
    	printf("%lld
    ",res);
    	return 0;
    }
    

    (C)

    因为树上所有直径有同一个中点或同一条中边,那么(dis)最小的点只能有(1)个或者两个

    然后我们从中点开始构造一条直径,如果无法构造出无解,否则剩下的点都可以挂在直径上而满足条件

    最后判一下构造出的直径是否满足它给出的(dis)即可

    const int N=105;
    int c[N],n,mn=233,mx;
    int main(){
    	scanf("%d",&n);
    	for(R int i=1,x;i<=n;++i)scanf("%d",&x),++c[x],cmin(mn,x),cmax(mx,x);
    	if(c[mn]>2)return puts("Impossible"),0;
    	fp(i,mn+1,mx)if(c[i]<2)return puts("Impossible"),0;
    	if(c[mn]==2&&mn!=mx-mn+1)return puts("Impossible"),0;
    	if(c[mn]==1&&mn!=mx-mn)return puts("Impossible"),0;
    	return puts("Possible"),0;
    }
    

    (D)

    这种题目显然是容斥了

    然而如果直接枚举有几个点选了不该选的数会有问题,因为有的点选不该选的数有两种方案,有的点选了别的点就不能选

    发现选了之后(i)只会影响(...,i-4k,i-2k,i+2k,i+4k,...)的数的选法,那么我们把所有模(2k)意义下相等的位置一起考虑,记(f_{i,j,0/1/2})表示考虑到这一类中的第(i)个数,选了其中(j)个,第(i)个数不选(/)选择在这个位置放(i-k/)选择在这个位置放(i+k)的方案数,转移即可,最后暴力加到全局的背包里,即可计算出(s[i])表示至少有这(i)个位置选择不合法的方案数,就可以直接套容斥了

    //quming
    #include<bits/stdc++.h>
    #define R register
    #define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
    #define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
    #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
    template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
    template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
    using namespace std;
    const int P=924844033;
    inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:0;}
    inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
    inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
    inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
    int ksm(R int x,R int y){
        R int res=1;
        for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
        return res;
    }
    const int N=2005;
    int n,k,res,len,f[N][3],g[N][3],s[N],t[N],fac[N];
    void calc(R int x){
    	memset(f,0,sizeof(f));
    	f[0][0]=1;
    	R int p=0;
    	for(;x<=n;x+=(k<<1)){
    		fp(i,0,p){
    			g[i][0]=f[i][0],g[i][1]=f[i][1],g[i][2]=f[i][2];
    			f[i][0]=f[i][1]=f[i][2]=0;
    		}
    		fp(i,0,p){
    			R int s=add(g[i][0],add(g[i][1],g[i][2]));
    			upd(f[i][0],s);
    			if(x>k)upd(f[i+1][1],dec(s,g[i][2]));
    			if(x+k<=n)upd(f[i+1][2],s);
    		}
    		++p;
    	}
    	memset(t,0,sizeof(t));
    	fp(i,0,len)fp(j,0,p)upd(t[i+j],mul(s[i],add(f[j][0],add(f[j][1],f[j][2]))));
    	len+=p;
    	fp(i,0,len)s[i]=t[i];
    }
    int main(){
    //	freopen("testdata.in","r",stdin);
    	scanf("%d%d",&n,&k);
    	fac[0]=1;fp(i,1,n)fac[i]=mul(fac[i-1],i);
    	s[0]=1;
    	fp(i,1,min(k<<1,n))calc(i);
    	fp(i,0,len)upd(res,i&1?dec(0,mul(fac[n-i],s[i])):mul(fac[n-i],s[i]));
    	printf("%d
    ",res);
    	return 0;
    }
    

    (E)

    博弈论菜鸡在此

    首先如果存在一个情况,(A)(u)(B)(v),如果(u)能走到的任何一条边在蓝树上到(v)的距离都小于等于(1)(A)只能等死了,否则如果存在一条边((u,v))满足蓝树上的距离大于(2),那么(A)就可以一直利用这条边绕(B)了,此时输出(-1)

    如果会被追到,那么以蓝树上的(Y)为根,我们发现(A)根本走不出这棵子树,那么我们找到所有(A)能到达的点,然后到其中深度最大的点等死就行了

    //quming
    #include<bits/stdc++.h>
    #define R register
    #define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
    #define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
    #define go(head,u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
    template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
    template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
    using namespace std;
    const int N=1e6+5;
    struct eg{int v,nx;}e[N<<1];int bl[N],rd[N],tot;
    inline void add(R int *head,R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
    int fr[N],to[N],dep[N],fa[N],dfn[N],low[N],ok[N],vis[N],dis[N],tim,n,S,T;
    void dfs(int *head,int u){
    	dfn[u]=++tim;
    	go(head,u)if(v!=fa[u])fa[v]=u,dep[v]=dep[u]+1,dfs(head,v);
    	low[u]=tim;
    }
    inline bool ck(R int u,R int v){
    	if(dfn[u]>dfn[v])swap(u,v);if(low[u]>=low[v])return dep[v]-dep[u]>2;
    	if(fa[u]==fa[v])return false;return true;
    }
    int q[N];
    void bfs(){
    	int h=1,t=0,u;q[++t]=S,vis[S]=1;
    	while(h<=t){
    		u=q[h++];
    		go(rd,u)if(!vis[v]){
    			dis[v]=dis[u]+1;
    			if(dis[v]<dep[v])vis[v]=1,q[++t]=v;
    		}
    	}
    }
    int main(){
    	scanf("%d%d%d",&n,&S,&T);
    	for(R int i=1,u,v;i<n;++i)scanf("%d%d",&u,&v),fr[i]=u,to[i]=v;
    	for(R int i=1,u,v;i<n;++i)scanf("%d%d",&u,&v),add(bl,u,v),add(bl,v,u);
    	dfs(bl,T);
    	for(R int i=1,u,v;i<n;++i){
    		u=fr[i],v=to[i];
    		if(ck(u,v))ok[u]=ok[v]=1;
    		else add(rd,u,v),add(rd,v,u);
    	}
    	bfs();
    	fp(i,1,n)if(vis[i]&&ok[i])return puts("-1"),0;
    	R int res=0;
    	fp(i,1,n)if(vis[i])cmax(res,dep[i]<<1);
    	printf("%d
    ",res);
    	return 0;
    }
    

    (F)

    先考虑如何计算单个(k),那么对于每个点分别计算贡献,一个点会被计入贡献的次数是({nchoose k}-sum_{vin son_u}{sz_vchoose k}),其中(sz_v)表示以(u)为根时(v)子树的大小

    那么(n)个点加起来就是(n imes {nchoose k}-sum_{i=1}^n cnt[i] imes {ichoose k}),把组合数拆成阶乘的形式就可以把后面看成一个卷积了,(NTT)即可

    //quming
    #include<bits/stdc++.h>
    #define R register
    #define fp(i,a,b) for(R int i=(a),I=(b)+1;i<I;++i)
    #define fd(i,a,b) for(R int i=(a),I=(b)-1;i>I;--i)
    #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
    template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
    template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
    using namespace std;
    const int P=924844033,gi=554906420;
    inline void upd(R int &x,R int y){(x+=y)>=P?x-=P:0;}
    inline int add(R int x,R int y){return x+y>=P?x+y-P:x+y;}
    inline int dec(R int x,R int y){return x-y<0?x-y+P:x-y;}
    inline int mul(R int x,R int y){return 1ll*x*y-1ll*x*y/P*P;}
    int ksm(R int x,R int y){
    	R int res=1;
    	for(;y;y>>=1,x=mul(x,x))(y&1)?res=mul(res,x):0;
    	return res;
    }
    const int N=(1<<19)+5;
    struct eg{int v,nx;}e[N<<1];int head[N],tot;
    inline void Add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
    int fac[N],ifac[N],r[25][N],rt[2][N],f[N],g[N],inv[25];
    int n,lim,d;
    inline void swap(R int &x,R int &y){R int t=x;x=y,y=t;}
    inline int C(R int n,R int m){return m>n?0:1ll*fac[n]*ifac[m]%P*ifac[n-m]%P;}
    void init(){
    	fac[0]=ifac[0]=1;fp(i,1,262144)fac[i]=mul(fac[i-1],i);
    	ifac[262144]=ksm(fac[262144],P-2);fd(i,262143,1)ifac[i]=mul(ifac[i+1],i+1);
        fp(d,1,19){
            fp(i,1,(1<<d)-1)r[d][i]=(r[d][i>>1]>>1)|((i&1)<<(d-1));
            inv[d]=ksm(1<<d,P-2);
        }
        for(R int t=(P-1)>>1,i=1,x,y;i<=262144;i<<=1,t>>=1){
            x=ksm(5,t),y=ksm(gi,t),rt[0][i]=rt[1][i]=1;
            fp(k,1,i-1)
                rt[1][i+k]=mul(rt[1][i+k-1],x),
                rt[0][i+k]=mul(rt[0][i+k-1],y);
        }
    }
    void NTT(int *A,int ty){
    	fp(i,0,lim-1)if(i<r[d][i])swap(A[i],A[r[d][i]]);
    	R int t;
    	for(R int mid=1;mid<lim;mid<<=1)
    		for(R int j=0;j<lim;j+=(mid<<1))
    			fp(k,0,mid-1)
    				A[j+k+mid]=dec(A[j+k],t=mul(rt[ty][mid+k],A[j+k+mid])),
    				A[j+k]=add(A[j+k],t);
    	if(!ty){
    		t=inv[d];
    		fp(i,0,lim-1)A[i]=mul(A[i],t);
    	}
    }
    int sz[N];
    void dfs(int u,int fa){
    	sz[u]=1;
    	go(u)if(v!=fa){
    		dfs(v,u),sz[u]+=sz[v];
    		++f[n-sz[v]],++f[sz[v]];
    	}
    }
    int main(){
    //	freopen("testdata.in","r",stdin);
    	scanf("%d",&n);
    	for(R int i=1,u,v;i<n;++i)scanf("%d%d",&u,&v),Add(u,v),Add(v,u);
    	dfs(1,0);init();
    	lim=1,d=0;
    	while(lim<=(n<<1))lim<<=1,++d;
    	fp(i,0,n)f[i]=mul(f[i],fac[i]),g[i]=ifac[n-i];
    	NTT(f,1),NTT(g,1);
    	fp(i,0,lim-1)f[i]=mul(f[i],g[i]);
    	NTT(f,0);
    	fp(i,1,n)printf("%d
    ",dec(mul(n,C(n,i)),mul(f[i+n],ifac[i])));
    	return 0;
    }
    
  • 相关阅读:
    Mysql::Error: Commands out of sync; you can't run this command now: SHOW TABLES解决方案
    mysql安装失败Error Nr. 1045
    TermServDevices 报错【远程服务使用者必读】
    数据库出现“提取逻辑页失败”
    Ruby学习——数据库操作
    VS2008 安装失败
    Ubuntu Server 安装图解
    C#的Enum——枚举
    SQLServer2005数据库被置为“可疑”
    ROR之include、extend、send对module、class进行扩展
  • 原文地址:https://www.cnblogs.com/yuanquming/p/11361628.html
Copyright © 2020-2023  润新知