Codeforces Round #663 (Div. 2) A-E总题解

Solution

A

由于无论 x x x与谁做或运算,结果均不会小于 x x x;所以,我们只需要输出 1 , 2 , … … n 1,2,……n 1,2,n,保证以 x x x结尾与 x x x开头的区间一定满足要求。

B

显然,最终所有的东西都会集中到底部或右侧;此时,我们只需要让最右边一列的字符全为 D D D,底侧的字符全为 R R R,即可满足要求

故答案为右侧 R R R的数量与底侧 D D D的数量之和。

C

显然,最大的数是不会往外连边的,其他的数一定会往外连至少一条边,故至少有 n − 1 n-1 n1条边。

反面考虑。由于有 n n n个顶点,我们要让它不成环,边的数量不能超过 n − 1 n-1 n1,即必须让该图成为一个树的形态才可以。故只能有 n − 1 n-1 n1条边

尝试构造一些满足"所有值非 n n n的节点向外连边的数量均为 1 1 1条"的排列,可以发现,这些排列都是单峰序列。峰左的数向它右边的数连边,峰右的数向它左边的数连边。

于是,现在我们思考如何求出单峰序列的数量。显然,峰值一定为 n n n。可以发现,只要选定了峰左哪些数出现了,那么整个序列都确定下来了。当 n n n被选做峰顶的时候,显然剩下有 n − 1 n-1 n1个数可选;设峰顶的位置为 k k k,则峰左的数有 C n − 1 k − 1 C_{n-1}^{k-1} Cn1k1种选择。

故答案为 n ! − ∑ i = 1 n C n − 1 i − 1 n!-\sum_{i=1}^n C_{n-1}^{i-1} n!i=1nCn1i1

这个式子可以进一步优化:

n ! − ∑ i = 1 n C n − 1 i − 1 n!-\sum_{i=1}^n C_{n-1}^{i-1} n!i=1nCn1i1

= n ! − 2 n − 1 =n!-2^{n-1} =n!2n1

于是,我们只需要使用普通幂与阶乘,并注意减法的取模方式即可通过本题。

时间复杂度 O ( n ) O(n) O(n)

D

首先,可以发现,对于一个 4 × 4 4×4 4×4的子矩阵,它是由四个 2 × 2 2×2 2×2的子矩阵组合而成的;而这四个 2 × 2 2×2 2×2的子矩阵各数之和必须都是奇数,故一个 4 × 4 4×4 4×4的子矩阵的各数之和只能是奇数的四倍,即偶数,不符题意。所以,可以推出,如果 n × m n×m n×m的矩形中含有任何一个 4 × 4 4×4 4×4的子矩阵,均应输出 − 1 -1 1。注意,当一个长方形含有 4 × 4 4×4 4×4的子矩阵时,当且仅当 n , m ≥ 4 n,m≥4 n,m4

此时,我们的长方形的长度为 n n n,宽度为 m m m,必有 n < 4 n<4 n4 m < 4 m<4 m4。不妨设 n ≥ m n≥m nm,即 m < 4 m<4 m4,显然这时长方形是一条宽度为 1 1 1 2 2 2 3 3 3的链。

于是,我们考虑状压 d p dp dp。由于每一行的状态并不多(最多 8 8 8个),可以考虑用一个压位十进制数表示每一位的状态,并暴力转移即可。注意,此时我们只需要保证任何 2 × 2 2×2 2×2的子矩阵中和为奇数,其他并无限制

总时间复杂度为 O ( k n m ) O(knm) O(knm),其中 k k k是一个巨大的常数,但是并不妨碍我们 A C AC AC本题。

E

比赛场上脑子瓦特, E E E没做出来QAQ

本题做法十分简单。首先,我们从 1 1 1号节点对整个图进行深搜,得到了每个节点的深度。对于第一个问题而言,如果有节点的深度达到了 ⌈ n 2 ⌉ \lceil \frac n 2 \rceil 2n,则直接递归打印该路径。

如果没达到呢?我们不得不开始思考问题 2 2 2。并不显然地发现,对于同深度的节点两两配对即可

为什么呢?首先,由于它们是同深度的,它们之间不会有边。同时,对于 p a i r ( a , b ) pair(a,b) pair(a,b) p a i r ( c , d ) pair(c,d) pair(c,d)(不妨设 a , b a,b a,b的深度小于 c , d c,d c,d的深度)不可能出现 ( a , b , c , d ) (a,b,c,d) (a,b,c,d)形成一个独立的连通图的情况。因为若形成连通图,不可能满足 a a a b b b属于同一深度且 c c c d d d属于同一深度,因为搜到 a a a的时候, a a a直接把另外三个点给全部搜了一遍。

所以,这种做法是正确的。

比赛的时候想到了不会证明不敢写QAQ

Code

A

#include <bits/stdc++.h>
#define int long long
using namespace std;

int t,n;
int a[200005];

signed main()
{
	cin>>t;
	while (t--)
	{
		cin>>n;
		for (int i=1;i<=n;i++)  cout<<i<<' ';
		cout<<endl;
	}
	return 0;
}

B

#include <bits/stdc++.h>
#define int long long
using namespace std;

int t,n,m;
char a[105][105];

signed main()
{
	cin>>t;
	while (t--)
	{
		cin>>n>>m;
		for (int i=1;i<=n;i++)
		{
			for (int j=1;j<=m;j++)  cin>>a[i][j];
		}
		int ans=0;
		for (int i=1;i<=n-1;i++)
		{
			if (a[i][m]!='D')  ans++;
		}
		for (int i=1;i<=m-1;i++)
		{
			if (a[n][i]!='R')  ans++;
		}
		cout<<ans<<endl;
	}
	return 0;
}

C

#include <bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7; 

int n;

int quick_power(int a,int b)
{
	int res=1;
	for (;b;b=b>>1,a=(a*a)%mod)
	{
		if (b&1)  res=(res*a)%mod;
	}
	return res;
}

signed main()
{
	cin>>n;
	int tot=1;
	for (int i=1;i<=n;i++)  tot=(tot*i)%mod;
	
	tot=((tot-quick_power(2,n-1))%mod+mod)%mod;
	cout<<tot<<endl;
	
	return 0;
}

D

#include <bits/stdc++.h>
#define int long long
#define inf 2000000007
using namespace std;

int n,m,x,ans=inf;
int dp[1000005][8];
char ch;

vector<int> a[1000005];
vector<int> b[1000005];

signed main()
{
	cin>>n>>m;
	if (n>=4&&m>=4)  return cout<<-1<<endl,0;
	for (int i=1;i<=n;i++)
	{
		for (int j=1;j<=m;j++)  cin>>ch,a[i].push_back(ch-'0');
	}
	if (n<m)//2 4
	{
		for (int i=1;i<=n;i++)
		{
			for (int j=1;j<=m;j++)  b[j].push_back(a[i][j-1]);
		}
		for (int i=1;i<=n;i++)  a[i].clear();
		swap(n,m);
		
		for (int i=1;i<=n;i++)
		{
			for (int j=0;j<m;j++)  a[i].push_back(b[i][j]);
		}
	}
	for (int i=1;i<=n;i++)
	{
		for (int j=0;j<8;j++)  dp[i][j]=inf;
	}
	if (m==1)  return cout<<0<<endl,0;
	else if (m==2)
	{
		for (int i=0;i<4;i++)
		{
			int x=i>>1,y=i&1;
			dp[1][i]=(a[1][0]!=x)+(a[1][1]!=y);
		}
		for (int i=2;i<=n;i++)
		{
			for (int j=0;j<4;j++)
			{
				int x=j>>1,y=j&1;
				for (int k=0;k<4;k++)
				{
					int X=k>>1,Y=k&1;
					if ((x+y+X+Y)%2)  dp[i][j]=min(dp[i][j],dp[i-1][k]);
				}
				dp[i][j]+=(a[i][0]!=x)+(a[i][1]!=y);
			}
		}
		for (int i=0;i<4;i++)  ans=min(ans,dp[n][i]); 
	}
	else if (m==3)
	{
		for (int i=0;i<8;i++)
		{
			int x=i>>2,y=(i>>1)&1,z=i&1;
			dp[1][i]=(x!=a[1][0])+(y!=a[1][1])+(z!=a[1][2]);
		}
		for (int i=2;i<=n;i++)
		{
			for (int j=0;j<8;j++)
			{
				int x=j>>2,y=(j>>1)&1,z=j&1;
				for (int k=0;k<8;k++)
				{
					int X=k>>2,Y=(k>>1)&1,Z=k&1;
					if ((x+y+X+Y)%2&&(y+z+Y+Z)%2)  dp[i][j]=min(dp[i][j],dp[i-1][k]);
				}
				dp[i][j]+=(a[i][0]!=x)+(a[i][1]!=y)+(a[i][2]!=z);
			}
		}
		for (int i=0;i<8;i++)  ans=min(ans,dp[n][i]); 
	}
	cout<<ans<<endl;
	
	return 0;
}

E

#include <bits/stdc++.h>
#define int long long
using namespace std;
 
int t,n,m,u,v,maxv=0,ans=0,cnt=0,pos;
int head[500005],visited[500005],depth[500005];
 
vector<int> a[500005];
 
struct edge
{
	int next;
	int to;
}e[2000005];
 
inline void add_edge(int u,int v)
{
	cnt++;
	e[cnt].to=v;
	e[cnt].next=head[u];
	head[u]=cnt;
}
 
inline int read()
{
	int s=0,w=1;
	char ch=getchar();
	
	while (ch<'0'||ch>'9')
	{
		if (ch=='-')  w=-w;
		ch=getchar();
	}
	while (ch>='0'&&ch<='9')
	{
		s=(s<<1)+(s<<3)+(ch^'0');
		ch=getchar();
	}
	return s*w;
}
 
inline void dfs(int now,int dep)
{
	a[dep].push_back(now);
	depth[now]=dep;
	visited[now]=1;
	
	if (depth[now]>maxv)
	{
		maxv=depth[now];
		pos=now;
	}
	for (int i=head[now];i;i=e[i].next)
	{
		if (!visited[e[i].to])  dfs(e[i].to,dep+1);
	}
}
 
inline void work(int now)
{
	if (depth[now]==1)
	{
		cout<<now<<' ';
		return;
	}
	for (int i=head[now];i;i=e[i].next)
	{
		if (depth[e[i].to]+1==depth[now])
		{
			work(e[i].to);
			break;
		}
	}
	cout<<now<<' ';
}
 
signed main()
{
	cin>>t;
	while (t--)
	{
		cin>>n>>m;
		maxv=0,cnt=0;
		for (int i=1;i<=n;i++)
		{
			head[i]=visited[i]=0;
			a[i].clear();
		}
		for (int i=1;i<=2*m;i++)  e[i].next=e[i].to=0;
		for (int i=1;i<=m;i++)
		{
			u=read(),v=read();
			add_edge(u,v);
			add_edge(v,u);
		}
		dfs(1,1);
		
		if (maxv>=(n+1)/2)
		{
			cout<<"PATH"<<endl;
			cout<<maxv<<endl;
			work(pos);
			cout<<endl;
			continue;
		}
		else
		{
			ans=0;
			for (int i=1;i<=n;i++)  ans+=a[i].size()/2;
			
			cout<<"PAIRING"<<endl;
			cout<<ans<<endl;
			for (int i=1;i<=n;i++)
			{
				if (a[i].size()<=1)  continue;
				for (int j=0;j<a[i].size()-1;j+=2)  cout<<a[i][j]<<' '<<a[i][j+1]<<endl;
			}
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值