zoukankan      html  css  js  c++  java
  • AtCoder Grand Contest 038 题解

    传送门

    这场表现的宛如一个(zz)

    (A)

    先直接把前(b)行全写成(1),再把前(a)列取反就行

    const int N=1005;
    char mp[N][N];int n,m,a,b;
    int main(){
    	scanf("%d%d%d%d",&n,&m,&a,&b);
    	fp(i,1,b)fp(j,1,m)mp[i][j]=1;
    	fp(i,1,n)fp(j,1,a)mp[i][j]^=1;
    	fp(i,1,n){
    		fp(j,1,m)putchar(mp[i][j]+'0');
    		putchar('
    ');
    	}
    	return 0;
    }
    

    (B)

    先除去区间内本就有序的情况,那么操作([i,i+k-1])([i+1,i+k])等价当且仅当(p_i)([i,i+k-1])中最小的元素且(p_{i+k})([i+1,i+k])中最大的元素,那么就不计算(i+1)就行了。用单调栈就能判断

    //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 N=2e5+5;
    int a[N],st[N],up[N],dw[N],dr[N],top,n,res,k,fl;
    int main(){
    	scanf("%d%d",&n,&k);
    	fp(i,1,n)scanf("%d",&a[i]);
    	st[top=0]=0;
    	fp(i,1,n){
    		while(top&&a[i]>a[st[top]])--top;
    		up[i]=(st[top]<=i-k),st[++top]=i;
    	}
    	st[top=0]=n+1;
    	fd(i,n,1){
    		while(top&&a[i]<a[st[top]])--top;
    		dw[i]=(st[top]>=i+k),st[++top]=i;
    	}
    	for(R int l=1,r=2;r<=n;l=r++){
    		while(r<=n&&a[r]>a[r-1])++r;
    		fp(i,l+k-1,r-1)dr[i]=1;
    	}
    	fp(i,k,n)if(dr[i])fl=1;
    		else if(!(up[i]&&dw[i-k]))++res;
    	printf("%d
    ",res+fl);
    	return 0;
    }
    

    (C)

    方便起见设

    [egin{aligned} Ans &=sum_{i=1}^nsum_{j=1}^n ext{lcm}(a_i,a_j) end{aligned} ]

    最后的答案减一减就行了

    然后开始颓柿子

    [egin{aligned} Ans &=sum_{i=1}^nsum_{j=1}^n ext{lcm}(a_i,a_j)\ &=sum_{d=1}^n dsum_{i=1}^nsum_{j=1}^n [d|a_i][d|a_j]{a_iover d}{a_jover d}[gcd({a_iover d},{a_jover d})=1]\ &=sum_{d=1}^n dsum_{i=1}^nsum_{j=1}^n [d|a_i][d|a_j]{a_iover d}{a_jover d}sum_{t|{a_iover d},t|{a_jover d}}mu(t)\ &=sum_{T=1}^n sum_{d|T}dsum_{i=1}^nsum_{j=1}^n [T|a_i][T|a_j]{a_iover T}{a_jover T} imes{T^2over d^2}mu({Tover d})\ &=sum_{T=1}^n sum_{i=1}^nsum_{j=1}^n [T|a_i][T|a_j]{a_iover T}{a_jover T}Tsum_{d|T}{Tover d}mu({Tover d})\ &=sum_{T=1}^n sum_{i=1}^nsum_{j=1}^n [T|a_i][T|a_j]{a_iover T}{a_jover T}Tsum_{d|T}dmu(d)\ end{aligned} ]

    (O(nlog n))预处理(s(T)=sum_{d|T}dmu(d)),然后记(cnt[k])表示(a_i=k)的个数,(O(nlog n))计算即可

    //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=998244353;
    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=1e6+5,L=1e6;
    bitset<N>vis;int p[N],mu[N],cnt[N],a[N],st[N],c[N],s[N],top,n,m,res;
    void init(int n=L){
    	mu[1]=1;
    	fp(i,2,n){
    		if(!vis[i])p[++m]=i,mu[i]=-1;
    		for(R int j=1;j<=m&&i*p[j]<=n;++j){
    			vis[i*p[j]]=1;
    			if(i%p[j]==0)break;
    			mu[i*p[j]]=-mu[i];
    		}
    	}
    	fp(i,1,n)upd(mu[i],P);
    	fp(i,1,n)for(R int j=i;j<=n;j+=i)upd(s[j],mul(i,mu[i]));
    }
    int main(){
    //	freopen("testdata.in","r",stdin);
    	scanf("%d",&n);
    	init();
    	fp(i,1,n)scanf("%d",&a[i]),++cnt[a[i]];
    	fp(T,1,L){
    		R int sum=0;
    		for(R int j=T;j<=L;j+=T)upd(sum,mul(j/T,cnt[j]));
    		sum=mul(sum,sum),sum=mul(sum,mul(T,s[T]));
    		upd(res,sum);
    	}
    	fp(i,1,n)res=dec(res,a[i]);
    	res=mul(res,(P+1)>>1);
    	printf("%d
    ",res);
    	return 0;
    }
    

    (D)

    先把(m=n-1)的情况特判掉,接下来只考虑(mgeq n)

    建一张新图(G),对于所有(C_i=0)的关系((a,b))看成(a,b)在同一个连通块里,这样缩完点之后对于每一个(C_i=1)的关系((a,b))必须满足(a,b)在不同连通块里否则无解

    记连通块个数为(k),如果我们从每个连通块中取出一个点,把所有给出的点连成一个环,每个连通块内随便连一棵生成树,这样总的边数为(n),且能保证任意两个处于不同连通块中的点之间至少(2)条路径,这就是边数的下界,且因为之前我们保证了(mgeq n)所以下界必然能达到

    再来考虑上界,每个连通块内连生成树,选出的点之间连完全图,边数就是(n-k+{k (k-1)over 2}=n+{k(k-3)over 2}),那么上界肯定是越大越好,也就是说我们不需要再加额外的边,直接用(G)中的边才能保证(k)最大

    (ps:)对于总的连通块个数为(1)(2)的边界情况都会在判上界的时候处理掉所以没必要讨论

    所以只要(mleq n+{k(k-3)over 2})就有解,否则无解

    //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;
    typedef long long ll;
    const int N=1e5+5;
    struct eg{int u,v,c;}e[N];
    ll m,sum;int fa[N],n,q;
    inline int find(R int x){return fa[x]==x?x:fa[x]=find(fa[x]);}
    int main(){
    	scanf("%d%lld%d",&n,&m,&q);
    	fp(i,1,n)fa[i]=i;
    	for(R int i=1,u,v;i<=q;++i){
    		scanf("%d%d%d",&e[i].u,&e[i].v,&e[i].c);
    		++e[i].u,++e[i].v;
    		if(!e[i].c)u=find(e[i].u),v=find(e[i].v),fa[u]=v;
    		if(e[i].c&&m==n-1)return puts("No"),0;
    	}
    	if(m==n-1)return puts("Yes"),0;
    	for(R int i=1,u,v;i<=q;++i)if(e[i].c){
    		u=find(e[i].u),v=find(e[i].v);
    		if(u==v)return puts("No"),0;
    	}
    	fp(i,1,n)sum+=(find(i)==i);
    	sum=n-sum+(1ll*sum*(sum-1)>>1);
    	puts(m<=sum?"Yes":"No");
    	return 0;
    }
    

    (E)

    首先,通过(Min-Max)容斥转化一下,问题变成对于一个集合(S),设(S={t_1,t_2,..,t_m}),其中第一个(t_i)出现次数到达(b_{t_i})时的期望步数

    我们设一个状态(x_1,x_2,..,x_m(x_i<b_{t_i})),表示(t_i)恰好出现了(x_i)次,设(P)表示生成的数在集合(S)中的概率,那么这个状态发生变化的期望步数就是({1over P}),同时如果能算出这个状态出现的概率(p),那么它对答案的贡献就是({pover P})了。如果对所有合法的(x)都能计算出贡献,加起来就是集合(S)中第一个(t_i)出现次数到达(b_{t_i})时的期望步数了

    对于(p),设(X=sum_{i=1}^m t_i),则有

    [egin{aligned} p=X!prod_{i=1}^mleft({t_iover P} ight)^{x_i}{1over x_i!} end{aligned} ]

    那么就可以算了,设(f[i][j][k])表示考虑到第(i)个数,其中选的集合中(X=j)(sum a=k)的总的贡献,最后对于每一个合法的状态加上贡献即可

    //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=998244353;
    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=405;
    int fac[N],ifac[N],bin[N],f[N][N][N],a[N],b[N],n,s1,s2;
    inline void init(R int n=400){
    	fac[0]=ifac[0]=1;fp(i,1,n)fac[i]=mul(fac[i-1],i);
    	ifac[n]=ksm(fac[n],P-2);fd(i,n-1,1)ifac[i]=mul(ifac[i+1],i+1);
    }
    int main(){
    //	freopen("testdata.in","r",stdin);
    	scanf("%d",&n);
    	init();
    	fp(i,1,n)scanf("%d%d",&a[i],&b[i]);
    	f[0][0][0]=P-1;
    	fp(i,1,n){
    		fp(j,0,s1)fp(k,0,s2)f[i][j][k]=f[i-1][j][k];
    		bin[0]=1;fp(j,1,b[i]-1)bin[j]=mul(bin[j-1],a[i]);
    		fp(j,0,b[i]-1)bin[j]=mul(bin[j],ifac[j]);
    		fp(j,0,s1)fp(k,0,s2)fp(v,0,b[i]-1)
    			upd(f[i][j+v][k+a[i]],P-mul(f[i-1][j][k],bin[v]));
    		s1+=b[i]-1,s2+=a[i];
    	}
    	R int res=0;
    	fp(i,0,s1)fp(j,1,s2){
    		R int ret=mul(f[n][i][j],fac[i]);
    		ret=mul(ret,ksm(j,P-1-i));
    		upd(res,mul(ret,mul(s2,ksm(j,P-2))));
    	}
    	printf("%d
    ",res);
    	return 0;
    }
    

    (F)

    首先,我们从(i)(p_i)连边,那么肯定是形成了若干个环,且环上所有数只能同时选(i)或者(p_i),我们记同时选(i)(1),同时选(p_i)(0)

    同理从(i)(q_i)连边,不过记同时选(i)(0),同时选(q_i)(1)

    然后记(x[i])(y[i])分别表示(i)处于哪个环,那么(i)是否有贡献是跟它所在的两个环的取值以及(p_i)(q_i)的值有关的,根据(p_i)(q_i)的取值讨论一下就行了

    懒得写讨论了直接贴题解(其中(v_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)
    #define gg(u) for(int &i=cur[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 N=5e5+5,M=1e6+5,inf=0x3f3f3f3f;
    inline int min(R int x,R int y){return x<y?x:y;}
    struct eg{int v,nx,w;}e[M];int head[N],tot=1;
    inline void add(R int u,R int v,R int w){
    	e[++tot]={v,head[u],w},head[u]=tot;
    	e[++tot]={u,head[v],0},head[v]=tot;
    }
    int dep[N],cur[N],S,T,n;
    bool bfs(){
    	memset(dep,-1,(T+1)<<2);
    	memcpy(cur,head,(T+1)<<2);
    	static int q[N];
    	int h=1,t=0,u;q[++t]=S,dep[S]=0;
    	while(h<=t){
    		u=q[h++];
    		go(u)if(e[i].w&&dep[v]<0)q[++t]=v,dep[v]=dep[u]+1;
    	}
    	return ~dep[T];
    }
    int dfs(int u,int lim){
    	if(u==T||!lim)return lim;
    	int fl=0,f;
    	gg(u)if(dep[v]==dep[u]+1&&(f=dfs(v,min(lim,e[i].w)))){
    		fl+=f,lim-=f,e[i].w-=f,e[i^1].w+=f;
    		if(!lim)break;
    	}
    	if(!fl)dep[u]=-1;
    	return fl;
    }
    inline int dinic(){R int res=0;while(bfs())res+=dfs(S,inf);return res;}
    int p[N],q[N],blp[N],blq[N],s0[N],s1[N],sum,cnt;
    int main(){
    //	freopen("testdata.in","r",stdin);
    	scanf("%d",&n);
    	fp(i,1,n)scanf("%d",&p[i]),++p[i];
    	fp(i,1,n)scanf("%d",&q[i]),++q[i];
    	fp(i,1,n)if(!blp[i]){
    		++cnt;
    		for(R int j=i;!blp[j];j=p[j])blp[j]=cnt;
    	}
    	fp(i,1,n)if(!blq[i]){
    		++cnt;
    		for(R int j=i;!blq[j];j=q[j])blq[j]=cnt;
    	}
    	S=0,T=cnt+1;
    	fp(i,1,n)sum+=p[i]!=q[i];
    	fp(i,1,n){
    		if(p[i]==q[i]){
    			if(p[i]==i)continue;sum+=2;
    			add(S,blp[i],1),add(blq[i],T,1),add(blp[i],blq[i],2);
    		}else{
    			if(p[i]==i)add(S,blq[i],1);
    			else if(q[i]==i)add(blp[i],T,1);
    			else add(blp[i],blq[i],1);
    		}
    	}
    	printf("%d
    ",sum-dinic());
    	return 0;
    }
    
  • 相关阅读:
    Oracle 推出 ODAC for Entity Framework 和 LINQ to Entities Beta版
    Entity Framework Feature CTP 5系列文章
    MonoDroid相关资源
    MSDN杂志上的Windows Phone相关文章
    微软学Android Market推出 Web Windows Phone Marketplace
    使用 Visual Studio Agent 2010 进行负载压力测试的安装指南
    MonoMac 1.0正式发布
    Shawn Wildermuth的《Architecting WP7 》系列文章
    使用.NET Mobile API即51Degrees.mobi检测UserAgent
    MongoDB 客户端 MongoVue
  • 原文地址:https://www.cnblogs.com/yuanquming/p/11565870.html
Copyright © 2011-2022 走看看