Codeforces Round #663 (Div. 2)

A. Suborrays

题解

构造一个序列使得任意区间按位或的答案大于等于区间长度,打个表发现好像啥都行,于是就瞎输出了

#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long LL;
typedef pair<int,int> PII;
#define X first
#define Y second
inline int read()
{
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
	return x*f;
}
int T,n;
int main()
{
	T=read();
	while(T--)
	{
		n=read();
		for(int i=1;i<n;i++)printf("%d ",i);
		printf("%d\n",n);
	}
	return 0;
}

B. Fix You

题解

一开始读错题了以为LRUD都有,结果发现只有RD,于是就只需要判下面是不是都是R,右边是不是都是D就好了

#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long LL;
typedef pair<int,int> PII;
#define X first
#define Y second
inline int read()
{
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
	return x*f;
}
int n,m,a[110][110];
char pic[110][110];
bool vis[110][110];
bool legal(int x,int y)
{
	return (x>=0 && x<n) && (y>=0 && y<m);
}
queue<PII> Q;
int main()
{
	for(int T=read();T;T--)
	{
		n=read();m=read();
		for(int i=0;i<n;i++)for(int j=0;j<m;j++)vis[i][j]=a[i][j]=0;
		for(int i=0;i<n;i++)scanf("%s",pic[i]);
		int cnt=0;
		for(int i=0;i<m-1;i++)if(pic[n-1][i]!='R')cnt++;
		for(int i=0;i<n-1;i++)if(pic[i][m-1]!='D')cnt++;
		printf("%d\n",cnt);
	}
	return 0;
}

C. Cyclic Permutations

题解

题目花里胡哨的说了一坨,反正推了一下发现满足题意的就是这个序列需要有一个谷底,那么我们反其道行之,求不存在谷底的排列有多少就行,设峰值\(n\)\(i\) 位置,那么我们剩下\(n-1\)个数就已经按顺序拍好了,有\(C_{n-1}^{i-1}\) 种方案,最后用\(n!\) 减去\(\sum_{i=0}^{n-1} C_{n-1}^i\) 即可,(其实那玩意就是\(2_{n-1}\) 没有发现)

#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long LL;
typedef pair<int,int> PII;
#define X first
#define Y second
inline int read()
{
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
	return x*f;
}
const int MOD=1000000007,maxn=1000010;
int n;
LL fac=1,inv[maxn],C[maxn],ans; 
int main()
{
	n=read();
	for(int i=1;i<=n;i++)fac=(fac*i)%MOD;	
	inv[1]=1;
	for(int i=2;i<=n;i++)inv[i]=((MOD-MOD/i)*inv[MOD%i])%MOD;
	C[0]=1;
	for(int i=1;i<=n-1;i++)C[i]=(C[i-1]*LL(n-i))%MOD*inv[i]%MOD;
	for(int i=1;i<=n;i++)ans=(ans+C[i-1])%MOD;
	printf("%lld\n",((fac-ans)%MOD+MOD)%MOD);
	return 0;
}

D. 505

题解

题目大意是给你一个01矩阵,问最少修改多少个数,使得这个矩阵的所有偶数边长的子正方形矩阵里面都有奇数个1。
很容易发现,当\(n>3\)的时候,存在一个\(4*4\) 的矩阵,里面还包含着4个\(2*2\) 的矩阵,这个肯定是矛盾的,所以就只讨论\(n<4\) 的情况。
\(n=1\) 的时候答案是0, 当\(n=2或者n=3\) 的时候就状压DP设\(dp[i][s]\) 表示当前在第\(i\) 列,第\(i\) 列的01摆法为S就可以了,复杂度是\(O(4*4*n/2)或者O(8*8*n/6)\)

#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long LL;
typedef pair<int,int> PII;
#define X first
#define Y second
inline int read()
{
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
	return x*f;
}
const int maxn=1000010,inf=maxn;
int n,m,a[4][maxn],dp[maxn][2][2],DP[maxn][8];
char s[4][maxn];
int main()
{
	n=read();m=read();
	if(n>=4)return puts("-1"),0;
	if(n==1)return puts("0"),0;
	for(int i=0;i<n;i++)scanf("%s",s[i]);
		for(int i=0;i<n;i++)
			for(int j=0;j<m;j++)a[i][j]=s[i][j]-'0';
	if(n==2)
	{
		for(int i=0;i<m;i++)dp[i][0][0]=dp[i][0][1]=dp[i][1][0]=dp[i][1][1]=inf;
		for(int i=0;i<2;i++)
			for(int j=0;j<2;j++)
				if(a[0][0]==i && a[1][0]==j)dp[0][i][j]=0;
				else dp[0][i][j]=1;
		for(int i=1;i<m;i++)
		{
			for(int jj=0;jj<2;jj++)
				for(int kk=0;kk<2;kk++)
				{
					int cnt=2;
					if(a[0][i]==jj)cnt--;
					if(a[1][i]==kk)cnt--;
					for(int j=0;j<2;j++)
						for(int k=0;k<2;k++)
							if((j+k+jj+kk)%2)dp[i][jj][kk]=min(dp[i][jj][kk],dp[i-1][j][k]+cnt);
				}
		}
		int ans=maxn;
		for(int i=0;i<2;i++)for(int j=0;j<2;j++)ans=min(ans,dp[m-1][i][j]);
		printf("%d\n",ans);
		return 0;
	}
	if(n==3)
	{
		for(int i=0;i<m;i++)for(int j=0;j<8;j++)DP[i][j]=inf;
		for(int i=0;i<8;i++)
		{
			int S1=i&1,S2=(i>>1)&1,S3=(i>>2)&1;
			int cnt=3;
			if(a[0][0]==S1)cnt--;
			if(a[1][0]==S2)cnt--;
			if(a[2][0]==S3)cnt--;
			DP[0][i]=cnt;
		}
		for(int i=1;i<m;i++)
		{
			for(int S=0;S<8;S++)
			{
				int S1=S&1,S2=(S>>1)&1,S3=(S>>2)&1;
//				printf("%d %d%d%d\n",S,S1,S2,S3);
				int cnt=3;
				if(a[0][i]==S1)cnt--;
				if(a[1][i]==S2)cnt--;
				if(a[2][i]==S3)cnt--;
				for(int s=0;s<8;s++)
				{
					int s1=s&1,s2=(s>>1)&1,s3=(s>>2)&1;
//					if(i==1 && S==6)printf("%d %d %d %d %d %d\n",s1,s2,s3,S1,S2,S3);
					if((S1+s1+S2+s2)%2 && (S2+s2+S3+s3)%2)DP[i][S]=min(DP[i][S],DP[i-1][s]+cnt);
				}
//				printf("%d %d %d\n",i,S,DP[i][S]);
			}
		}
//		for(int i=0;i<m;i++)for(int S=0;S<8;S++)printf("%d %d %d\n",i,S,DP[i][S]);
		int ans=maxn;
		for(int i=0;i<8;i++)ans=min(ans,DP[m-1][i]);
		printf("%d\n",ans);
	}
	return 0;
}

E. Pairs of Pairs

题解

又是一道很诡异的题,题目大意是给你一个无向图,你要不在图中找到一个长度大于等于\(\lceil \frac{n}{2} \rceil\) 的简单路径,要不就找若干个二元组(其中这些二元组的元素不能重复,至少要多于等于\(\lceil \frac{n}{2} \rceil\) ),使得任意两个二元组组成的子图,至多有两条边。
直接看了题解,题解是随便找一点开始求他的dfs树,如果dfs树中有深度大于等于\(\lceil \frac{n}{2} \rceil\) 的点,就直接输出即可,否则就找所有深度相同的点,两两配对,一定能保证配出\(\lceil \frac{n}{4} \rceil\) 对。怎么证明呢?
先证这任意两个二元组组成的子图吧,根据dfs树的性质,所有非树边一定是祖先连往子孙,不可能存在子树之间的连边 ,深度相同的点显然是属于两个子树,所以保证两个二元组\((a,b),(c,d)\) 其中\(deep[a]=deep[b],deep[c]=deep[d]\)\(deep[a]<deep[c]\),a和b 不可能连边,c和d不可能连边,那两条边只可能是a和c,b和d为父子关系的时候才可以算上。
再证一定大于\(\lceil \frac{n}{4} \rceil\) 对,因为不存在深度大于\(\lceil \frac{n}{2} \rceil\) 了,所以最大深度不过\(\lceil \frac{n}{2} \rceil\) ,每一个深度只有当有0个或者1个节点的时候才会放弃这个深度,根据抽屉原理一定能选出\(\lceil \frac{n}{4} \rceil\) 对满足。

#include<bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
typedef long long LL;
typedef pair<int,int> PII;
#define X first
#define Y second
inline int read()
{
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
	return x*f;
}
const int maxn=500010,maxm=1000010;
int n,m,a,b,deep[maxn],pa[maxn],max_deep;
vector<int> G[maxn],deep_pair[maxn];
bool path,vis[maxn];
void dfs(int now,int fa)
{
	vis[now]=1;
	pa[now]=fa;
	if(path)return;
	deep_pair[deep[now]].push_back(now);
	max_deep=max(max_deep,deep[now]);
	if(deep[now]>=(n+1)/2)
	{
		int tmp=now;
		printf("PATH\n%d\n",deep[now]);
		while(tmp!=1)printf("%d ",tmp),tmp=pa[tmp];
		puts("1");
		path=1;
		return;
	}
	for(int v:G[now])
		if(v!=fa && !vis[v])
			deep[v]=deep[now]+1,dfs(v,now);
}
int main()
{
	for(int T=read();T;T--)
	{
		n=read();m=read();
		max_deep=path=0;
		for(int i=1;i<=n;i++)G[i].clear(),vis[i]=0;
		for(int i=1;i<=m;i++)a=read(),b=read(),G[a].push_back(b),G[b].push_back(a);
		deep[1]=1; 
		dfs(1,0);
		if(!path)
		{
			int cnt=0;
			for(int i=2;i<=max_deep;i++)cnt+=deep_pair[i].size()/2;
			printf("PAIRING\n%d\n",cnt);
//			for(int i=1;i<=max_deep;i++)
//			{
//				printf("deep %d:",i);
//				for(int j=0;j<deep_pair[i].size();j++)printf("%d ",deep_pair[i][j]);
//				puts("");
//			}
			for(int i=2;i<=max_deep;i++)
			{
				for(int j=0;j+1<deep_pair[i].size();j+=2)printf("%d %d\n",deep_pair[i][j],deep_pair[i][j+1]);
			}
		}
		for(int i=1;i<=max_deep;i++)deep_pair[i].clear();
	} 
	return 0;
}

废话

posted @ 2020-08-11 20:33  小飞淙的云端  阅读(47)  评论(0编辑  收藏