zoukankan      html  css  js  c++  java
  • AtCoder Regular Contest 093

    AtCoder Regular Contest 093


    C - Traveling Plan

    题意:

    给定n个点,求出删去i号点时,按顺序从起点到一号点走到n号点最后回到起点所走的路程是多少。

    (nle 2e5)

    分析:

    可以通过观察发现,无论删去那个点,比全部都走所差距的距离都是(|a_i-a_{i-1}|-|a_{i+1}-a_i|+|a_{i-1}-a_{i+1}|)
    所以直接枚举即可。

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN=1e5+7;
    int a[MAXN],n,ans;
    int main()
    {
    	cin>>n;
    	for(int i=1;i<=n;i++) cin>>a[i];
    	for(int i=1;i<=n+1;i++) ans+=abs(a[i]-a[i-1]);
    	for(int i=1;i<=n;i++){
    		cout<<ans-abs(a[i]-a[i-1])-abs(a[i]-a[i+1])+abs(a[i-1]-a[i+1])<<endl;
    	}
    }
    

    D - Grid Components

    题意:

    求一个边长均小于等于100的矩阵,涂成黑白两色,使得白色连通块和黑色连通块的数量分别是A、B。输出这个矩阵的长宽,并输出这个矩阵的具体涂色方案('.'是白色,'#'是黑色)。

    (1le A,B le 500)

    分析:

    经过观察发现100×100的矩阵一定可以满足所有要求。

    那么这么构造,首先把上下两部分平分开,上面是白色下面是黑色,然后一个一个的在白色里填充黑色,黑色同理。

    填充方法是从头开始每隔一行一列就填一个,可以证明这样填上下两个矩阵每个矩阵都可以填600个以上所以可以轻松满足要求。

    #include <bits/stdc++.h>
    using namespace std;
    int a,b;
    char ch[201][201];
    int main()
    {
    	for(int i=1;i<=50;i++)
    		for(int j=1;j<=100;j++)
    			ch[i][j]='.';
    	for(int i=51;i<=100;i++)
    		for(int j=1;j<=100;j++)
    			ch[i][j]='#';
    	cin>>a>>b;
    	a--;b--;
    	int cnt1=0,cnt2=0;
    	for(int i=1;i<=50;i+=2){
    		if(cnt1==b) break;
    		for(int j=1;j<=100;j+=2){
    			if(cnt1==b) break;
    			cnt1++;
    			ch[i][j]='#';
    		}
    	}
    	for(int i=52;i<=100;i+=2){
    		if(cnt2==a) break;
    		for(int j=1;j<=100;j+=2){
    			if(cnt2==a) break;
    			cnt2++;
    			ch[i][j]='.';
    		}
    	}
    	cout<<"100 100"<<endl;
    	for(int i=1;i<=100;i++){
    		for(int j=1;j<=100;j++){
    			cout<<ch[i][j];
    		}
    		cout<<endl;
    	}
    }
    

    E - Bichrome Spanning Tree

    题意:

    给出一个N个点M条边的无向图,现在要给一些边染黑色或者白色,现在从这些边中选出一些边生成若干棵生成树,要求这些生成树至少包含一条白色的边和一条黑色的边,而且这些生成树的最小值是X,问有多少种染色方法。

    分析:

    先求一下最小生成树并且设其权值和为s。

    那么分情况讨论一下,对于(s>x) 的情况,明显答案是0;

    对于(s=x)的情况,我们可以确定求得那棵树一定是这个最小生成树,所以记录一下所有在最小生成树中的边。那么这些边之外的边就可以随意染色,然后保证最小生成树中的边不是全黑或者全白就可以了。容易得出答案是(2^{M-m} imes(2^m-1))种。

    首先必须把S里面的的所有边涂成黑色(或者白色),先假设全部涂成黑色,那么剩余的边,对每一条边单独处理,对边e,它染成白色添加进去之后,如果和集合S中的边形成的满足题意的最小生成树权重w′小于X,那么这条边只能继续涂成黑色;如果w′大于X,它涂成黑色白色都无所谓;然后把w′等于X的边的数量统计下来,假设有tot条边,可以知道这tot条边只要有一条边是白色就行了,因为只要选中这里面的一条边,剩余的边肯定都是从集合S中选出来了, 不可能再从其它边中选取,如果必须涂成黑色的有d条边, 那么答案就是2M−tot−d∗(2tot−1),最终结果再乘以2就行了,就是必须涂成一种颜色的有两种涂法

    (借鉴自:AtCoder Regular Contest 093(E-Bichrome Spanning Tree)

    #include <bits/stdc++.h>
    using namespace std;
    const int MAXN=2010;
    #define ll long long
    #define int ll
    const int mo=1e9+7;
    struct po
    {
    	int x,y,l;
    }a[MAXN];
    bool cmp(po a,po b){return a.l<b.l;}
    int n,m,tmp,x;
    int f[MAXN];
    int find(int x) {return x==f[x]?x:f[x]=find(f[x]);}
    int kruskal(int now)
    {
    	int res=0;
    	for(int i=1;i<=n;i++) f[i]=i;
    	if(now) {res+=a[now].l;f[a[now].x]=a[now].y;}
    	for(int i=1;i<=m;i++){
    		int r1=find(a[i].x),r2=find(a[i].y);
    		if(r1==r2) continue;
    		res+=a[i].l;
    		f[r1]=r2;
    	}
    	return res;
    }
    inline int power(int x,int k)
    {
    	int cnt=1;
    	while(k){
    		if(k&1) cnt=cnt*x%mo;
    		k>>=1;
    		x=x*x%mo;
    	}
    	return cnt;
    }
    int val,cnt1,cnt2;
    int ans;
    main()
    {
    	cin>>n>>m>>x;
    	for(int i=1;i<=m;i++) cin>>a[i].x>>a[i].y>>a[i].l;
    	sort(a+1,a+m+1,cmp);
    	tmp=kruskal(0);
    	if(tmp>x){
    		cout<<0;
    		return 0;
    	}
    	if(tmp==x){
    		for(int i=1;i<=m;i++){
    			val=kruskal(i);
    			if(val==x) cnt1++;
    			else cnt2++;
    		}
    		ans=((power(2,cnt1)-2)*power(2,cnt2)%mo+mo)%mo;
    	} else {
    		for(int i=1;i<=m;i++){
    			val=kruskal(i);
    			if(val==x) cnt1++;
    			else if(val>x) cnt2++;
    		}
    		ans=(2*(power(2,cnt1)-1)%mo*power(2,cnt2)%mo+mo)%mo;
    	}
    	cout<<ans;
    }
    

    F - Dark Horse

    题意:

    有2N个选手参与一场比赛,比赛规则是:相邻的两个人比赛一次,败者淘汰掉,胜者继续进行,直到只剩一个人为止。现在给出1号选手会败给哪些选手并且已知其他选手之间均满足:两个选手比赛,编号小的一定会胜利。现在可以安排每个选手初始的位置,要钦定1号选手最后获胜,求能满足条件的初始位置的方案数。

    分析:

    由于可以明显发现1号无论站在哪里最后的胜负方案数都是一样的,所以可以直接就让1号在一号位置,然后将答案最后乘上(2^n)即可。

    考虑1号一定会打n场,而且每次都会和(2^n+1...2^{n+1})中编号最小的人打,所以保证其中没有人在ad这个集合内就可以了。

    以下部分摘自dalao:

    接下来就是本题最有趣的地方了:容斥原理。
    设S为N个块的一个子集,(f(S))表示这个子集中所有块的最小值均在A的范围内(其余块是否在A的范围内不考虑)的方案数。

    这样一来,最终答案即为(∑(−1)^{|S|}f(S))
    将A从大到小排序,依次考虑加入(A_i)后的(f(S))
    1、成为一个块的最小值:那么在这个块中,必须填充相应数量的,编号比AiAi大的选手,组合数统计。
    2、不成为块的最小值,不操作即可((dp[i][S]+=dp[i−1][S]))

    #include <bits/stdc++.h>
    using namespace std;
    #define ll long long
    #define int ll
    const int MAXN=20;
    const int MAXM=2<<16+1;
    const int mo=1e9+7;
    int n,m,a[MAXN],bit[MAXN],c[MAXM];
    int fac[MAXM],inv[MAXM],dp[MAXN][MAXM];
    int power(int x,int k)
    {
    	int cnt=1;
    	while(k){
    		if(k&1) cnt=cnt*x%mo;
    		x=x*x%mo;
    		k>>=1;
    	}
    	return cnt;
    }
    int C(int x,int y){return 1ll*fac[x]*inv[y]%mo*inv[x-y]%mo;}
    main()
    {
    	cin>>n>>m;
    	for(int i=1;i<=m;i++) cin>>a[i];
    	reverse(a+1,a+m+1);
    	for(int i=0;i<=n-1;i++) bit[i]=1<<i;
    	int cnt=1<<n;fac[0]=1;
    	for(int i=1;i<=cnt;i++)
    		fac[i]=1ll*fac[i-1]*i%mo;
    	inv[cnt]=power(fac[cnt],mo-2);
    	for(int i=cnt-1;i>=0;i--)
    		inv[i]=inv[i+1]*(i+1ll)%mo;
    	int u=(1<<n)-1;dp[0][0]=1;
    	for(int i=1;i<=m;i++)
    		for(int s=0;s<=u;s++){
    			int l=cnt-a[i]+1-s;
    			dp[i][s]=(dp[i][s]+dp[i-1][s])%mo;
    			for(int j=0;j<=n-1;j++){
    				if(l<bit[j]) break;
    				if(bit[j]&s) continue;
    				dp[i][s^bit[j]]=(dp[i][s^bit[j]]+(1ll*dp[i-1][s]*C(l-1,bit[j]-1))%mo*fac[bit[j]]%mo)%mo;
    			}
    		}
    	int ans=fac[cnt-1]; c[0]=1;
    	for(int s=1;s<=u;s++){
    		c[s]=-c[s-(s&-s)];
    		ans=(ans+1ll*c[s]*dp[m][s]*fac[cnt-1-s]%mo)%mo;
    	}
    	ans=(1ll*ans*cnt%mo+mo)%mo;
    	cout<<ans;
    }
    
  • 相关阅读:
    Java 实现常见内排序
    markdown基本语法
    HashMap (JDK1.8) 分析
    jQuery总结
    JS 数组 常用方法
    CSS样式 解决文字过长显示省略号问题
    Python中的 __name__属性的含义和作用
    http协议详细介绍
    Http和Https的区别
    爬虫——requests库使用方法
  • 原文地址:https://www.cnblogs.com/victorique/p/9692133.html
Copyright © 2011-2022 走看看