题解 - Codeforces Round #632 (Div. 2)

C o d e f o r c e s   R o u n d   632   ( D i v . 2 ) \mathrm{Codeforces\ Round \ 632 \ (Div. 2) } 完整题解

我总算上橙了。。。。

A \mathrm{A}

题目意思

  • A
  • 给你 n m n*m 的矩阵,只有 B B W W ,相邻有其他不一样的点叫做好点,还需要让好点 B B 的数量多于 W W

S o l \mathrm{Sol}

  • 睿智构造
  • 一分钟写完,只要把 a ( 1 , 1 ) a(1,1) 涂成 W W 即可

C o d e \mathrm{Code}

#include <bits/stdc++.h>
#define pb push_back
using namespace std;

inline int read()
{
	int sum=0,ff=1; char ch=getchar();
	while(!isdigit(ch))
	{
		if(ch=='-') ff=-1;
		ch=getchar();
	}
	while(isdigit(ch))
		sum=sum*10+(ch^48),ch=getchar();
	return sum*ff;
}

int a[111][111],n,m,T;

int main()
{
	int T=read();
	for (;T--;)
	{
		n=read();
		m=read();
		a[1][1]=1;
		for ( int i=1;i<=n;i++ ) 
		{
			for ( int j=1;j<=m;j++ ) 
				if(a[i][j]) putchar('W');
				else  putchar('B');
			puts("");
		}
	}
}

B \mathrm{B}

题目意思

  • B
  • 给你一个数组 A A A i [ 1 , 0 , 1 ] A_i∈[-1,0,1] 。称一次操作 ( i , j ) , i < j (i,j),i<j 为: a j = a i + a j a_j=a_i+a_j 。问是否能通过若干次操作让他变成 B B

S o l \mathrm{Sol}

  • 首先:我的做法比较麻烦
  • 我们先记录原序列 A A 1 , 1 1,-1 的数量。我们重前往后找,如果存在 A i < B i A_i<B_i 那么前面一定存在 A i = 1 A_i=1 。如果存在 A i > B i A_i>B_i 那么前面一定存在 A i = 1 A_i=-1 。于是就直接模拟即可。注意 1 , 1 1,-1 个数的更新。

C o d e \mathrm{Code}

#include <bits/stdc++.h>
#define pb push_back
using namespace std;

inline int read()
{
	int sum=0,ff=1; char ch=getchar();
	while(!isdigit(ch))
	{
		if(ch=='-') ff=-1;
		ch=getchar();
	}
	while(isdigit(ch))
		sum=sum*10+(ch^48),ch=getchar();
	return sum*ff;
}

const int N=1e5+5;

int n,m,a[N],b[N]; 

int main()
{
	int T=read();
	for (;T--;)
	{
		n=read();
		int s0=0,s1=0,s2=0;
		for ( int i=1;i<=n;i++ ) 
			a[i]=read();
		for ( int i=1;i<=n;i++ )
		{
			b[i]=read();
		}
		for ( int i=1;i<=n;i++ )
		{
			if(a[i]==b[i])
			{
				if(a[i]==1) s1++;
				if(a[i]==-1) s2++;
				continue;
			}
			if(a[i]<b[i])
			{
				if(s1)
				{
					if(b[i]==-1) s2++;
					if(b[i]==1) s1++;
				}
				else 
				{
					printf("NO\n");
					goto rp;
				}
				if(a[i]==-1) s2++;
				if(a[i]==1) s1++;
			}
			if(a[i]>b[i])
			{
			
				if(s2)
				{
					if(b[i]==-1) s2++;
					if(b[i]==1) s1++;
				}
				else 
				{
					printf("NO\n");
					goto rp;
				}	
				if(a[i]==-1) s2++;
				if(a[i]==1) s1++;
			}
		}
		printf("YES\n");
		rp:;
	}
}
		

C \mathrm{C}

题目意思

  • C
  • 给定长度为 n n 的序列,定义序列 A A 好的,当且仅当: a a 的子段中不存在 s u m sum 值为0。

S o l \mathrm{Sol}

  • 我是先做了一遍前缀和,再尺取法了一下。
  • 也就是:若 s u m a i sum_{a_i} i i 前面存在,那么这样的序列只能最后一次取到 s u m a i sum_{a_i} 的下标 k k 以后,数量为 i k i - k

C o d e \mathrm{Code}

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

inline int read()
{
	int sum=0,ff=1; char ch=getchar();
	while(!isdigit(ch))
	{
		if(ch=='-') ff=-1;
		ch=getchar();
	}
	while(isdigit(ch))
		sum=sum*10+(ch^48),ch=getchar();
	return sum*ff;
}

const int N=2e5+5;

int n,m,a[N],sum[N],l,r,ans;
map<int,int> mp;

signed main()
{
	n=read();
	for ( int i=1;i<=n;i++ )
	{
		a[i]=a[i-1]+read();
		mp[a[i]]=0;
	}
	mp[0]++;
	mp[a[1]]++;
	int l=1,r=1;
	while(l<=n)
	{
		while(r<n&&!mp[a[r+1]]) mp[a[++r]]++;
		if(mp[a[l]]<=1)
            ans+=r-l+1;
		mp[a[l-1]]--;
		l++;
	}
	printf("%lld\n",ans);
	return 0;
}
		

D \mathrm{D}

题目意思

  • D
  • 给你一个含 R , L R,L 序列就是称一次操作可以将若干 R L RL 对翻转,问能否在 k k 次使得序列无法翻转。
  • n 3 e 3 , k 3 e 6 n\leq 3e3,k\leq 3e6

S o l \mathrm{Sol}

  • 一道比较 ** 的构造题目

  • 我们首先考虑如何使得答案最优,我们是不是只要每次能翻就翻。我们记录这个最少翻转次数为 m i mi

  • 同理,我们再考虑如何使得答案最差,我们是不是只要每次能翻只翻转一个。我们记录这个最大翻转次数为 m x mx

  • 对于无解的情况即: k < m i k<mi 或者 k > m x k>mx ,这个很好理解

  • 那么这样就简单了,我们只要去凑数字。即如果 m i < k mi<k ,那么我们就选择最差的方式去反转直到 m i = k mi=k 。对于剩下的我们选择用最优秀的方法翻转即可。这样就可以构造一个合法的答案了。

C o d e \mathrm{Code}

#include <bits/stdc++.h>
#define pb push_back
using namespace std;

inline int read()
{
	int sum=0,ff=1; char ch=getchar();
	while(!isdigit(ch))
	{
		if(ch=='-') ff=-1;
		ch=getchar();
	}
	while(isdigit(ch))
		sum=sum*10+(ch^48),ch=getchar();
	return sum*ff;
}

const int N=3005;

int n,m,ans,a[N],b[N],tmp[N],mi,mx;
char ch[N];

int main()
{
	n=read();
	m=read();
	scanf("%s",ch+1);
	for ( int i=1;i<=n;i++ ) 
	{
		a[i]=(ch[i]=='R')?1:-1;
		b[i]=a[i];
	}
	while(1)
	{
		int flg=0;
		for ( int i=1;i<n;i++ ) 
			if(a[i]==1&&a[i+1]==-1) 
			{
				flg=1;
				swap(a[i],a[i+1]);
				i++;
				mx++;
			}
		if(!flg) break;
		mi++;
	}
	if(m<mi||m>mx) return printf("-1\n"),0;
	for ( int i=1;i<=n;i++ ) a[i]=b[i];
	while(1)
	{
		int i=1;
		for(;i<n;++i)
		{
			if(m==mi) break;
			if(a[i]==1&&a[i+1]==-1) 
			{
				swap(a[i],a[i+1]);
				m--;
				printf("%d %d",1,i);
				puts("");
				i++;
			}
		}
		int gs=0;
		for(;i<n;++i)
		{
			if(a[i]==1&&a[i+1]==-1)
			{
				swap(a[i],a[i+1]);
				tmp[++gs]=i;
				i++; 
			}
		}
		if(gs)
		{
			printf("%d ",gs);
			for ( int j=1;j<=gs;j++ ) printf("%d ",tmp[j]);
			m--;
			puts("");
		}
		mi--;
		if(!m) break;
	}
	return 0;
}
		

E \mathrm{E}

题目意思

S o l \mathrm{Sol}

  • 首先 n 2 n\leq 2 是无解的

  • 对于有解的情况我们考虑皇后先按照车走的方法走(即这时候不会产生贡献)然后我们再强制皇后不优秀的方法走,那么我们有如下的构造方法:

  • 我们构造一个 2 × 3 2\times 3 的矩形使得把皇后逼到 2 × 3 2\times3 那一格,然后这个时候强制让皇后花费 1 1 走到 1 × 1 1\times 1 那一格子就可以了。

  • 于是车就用微小的优势获胜了。

  • 一下构造就很简单了,具体看代码。

C o d e \mathrm{Code}

#include <bits/stdc++.h>
#define pb push_back
using namespace std;

inline int read()
{
	int sum=0,ff=1; char ch=getchar();
	while(!isdigit(ch))
	{
		if(ch=='-') ff=-1;
		ch=getchar();
	}
	while(isdigit(ch))
		sum=sum*10+(ch^48),ch=getchar();
	return sum*ff;
}

const int N=505;

int n,m,a[N][N],ans;

int main()
{
	n=read();
	if(n<3) return printf("-1\n"),0;
	for ( int i=n;i>3;i-- ) a[1][i]=++m;
	for ( int i=4;i<=n;i++ ) a[2][i]=++m;
	for ( int i=3;i<n;i++ ) 
	{
		if(i&1)
			for ( int j=n;j>=1;j-- ) a[i][j]=++m;
		else 
			for ( int j=1;j<=n;j++ ) a[i][j]=++m;
	}
	if(n&1) 
	{
		for ( int j=n;j>=1;j-- ) 
			if(j!=2) a[n][j]=++m;
	}
	else 
		for ( int j=1;j<=n;j++ ) 
			if(j!=2) a[n][j]=++m;
	a[n][2]=++m;
	a[1][2]=++m,a[2][1]=++m,a[2][2]=++m,a[1][3]=++m,a[2][3]=++m;
	a[1][1]=++m;
	for ( int i=1;i<=n;i++,puts("") ) 
		for ( int j=1;j<=n;j++ )	
			printf("%d ",a[i][j]);
	return 0;
}

F \mathrm{F}

  • 做出 D i v 2 F Div2F 第一次啊!这是真的水呀

题目意思

  • F
  • [ 1 , n ] [1,n] 的连续自然数。对 [ 2 , n ] [2,n] 的每个 k k ,都枚举所有大小恰好为 k k 的子集,然后定义一个函数 F F F F 参数是一个集合,其遍历集合中所有的二元组,求出二元组的 g c d gcd ,然后取这些 g c d gcd 里面的最大值,对每个 k k 求函数 F F 的最小值。

S o l \mathrm{Sol}

  • 首先我们考虑如何最优秀:即先加入所有的质数,再加 2..3 2..3 的倍数。然后加到一个合数,他所有的因子必定存在于已有的集合(因为是一个一个加上去的 2.. n 2..n )。那么把每个数的最大因子搞出来,排遍序输出即可。

C o d e \mathrm{Code}

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


inline int read()
{
	int sum=0,ff=1; char ch=getchar();
	while(!isdigit(ch))
	{
		if(ch=='-') ff=-1;
		ch=getchar();
	}
	while(isdigit(ch))
		sum=sum*10+(ch^48),ch=getchar();
	return sum*ff;
}

const int N=5e5+5;

int n,tot,cnt[N],vis[N],alb[N],d[N];
vector<int> G[N];

inline void init()
{
	vis[1]=d[1]=1;
	for(int i=2;i<=n;i++)
	{
		if(!vis[i])
			alb[++tot]=d[i]=i;
		for(int j=1;j<=tot && i*alb[j]<=n;j++)
		{
			vis[i*alb[j]]=1;d[i*alb[j]]=alb[j];
			if(i%alb[j]==0)break;
		}
	}
}

signed main()
{
	n=read();
	int sum=1,i=1;
	init();
	for(int i=1;i<=n;i++) vis[i]=0;
	for(int i=2;i<=n;i++) d[i]=i/d[i];
	sort(d+1,d+n+1);
	for(int i=2;i<=n;i++)  printf("%d ",d[i]);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/wangyiyang2/article/details/105408165
今日推荐