Codeforces Round #630 (Div. 2)(A~E)题解

Codeforces Round #630 A~E

  • A.Exercising Walk
  • B.Composite Coloring
  • C.K-Complete Word
  • D.Walk on Matrix
  • E. Height All the Same

A.Exercising Walk

给定一个初始点x,y,你只可以在 [ x 1 , x 2 ] ∗ [ y 1 , y 2 ] [x1,x2]*[y1,y2] [x1,x2][y1,y2]范围内活动,你需要向上下左右分别移动 a , b , c , d a,b,c,d a,b,c,d步,次序可以打乱,问能否不超出这个范围走完.

题解:特判就完了,同一方向作差取绝对值,看看超没超出范围.
如果 x 1 = = x 2 x1 == x2 x1==x2 或者 y 1 = = y 2 y1 == y2 y1==y2要特殊考虑

#include
using namespace std;
typedef long long ll;
int t;
bool flag=true;
void solve(){
	ll a,b,c,d,x,y,x1,y1,x2,y2;
	scanf("%d",&t);
	while(t--){
		flag=true;
		scanf("%lld%lld%lld%lld%lld%lld%lld%lld%lld%lld",&a,&b,&c,&d,&x,&y,&x1,&y1,&x2,&y2);
		if(a>b&&x-(a-b)<x1) flag=false;
		if(a<b&&x+(b-a)>x2) flag=false;
		if(c>d&&y-(c-d)<y1) flag=false;
		if(c<d&&y+(d-c)>y2) flag=false;
		if(x1==x2&&(a!=0||b!=0)) flag=false;
		if(y1==y2&&(c!=0||d!=0)) flag=false;
		printf("%s\n",flag?"Yes":"No");
	}
}
int main(void)
{
	solve();
	return 0;
}

B.Composite Coloring

给出n个整数,然后最多用11种颜色,问能否把这些数都分配一个颜色,使得每种颜色的数两两的 g c d gcd gcd大于 1 1 1.

题解:
直接写出前 11 11 11个质数,因为输入的都是合数,只要判断这个合数被前 11 11 11个质数中的哪一个整除即可

#include
using namespace std;
typedef long long ll;
int a[11]={2,3,5,7,11,13,17,19,23,29,31};
int t,n,num,len,tot;
vector<int> lis;
map<int,int> mp;
void solve(){
	scanf("%d",&t);
	while(t--){
		tot=0;
		lis.clear();
		mp.clear();
		scanf("%d",&n);
		for(int i=1;i<=n;++i){
			scanf("%d",&num);
			for(int j=0;j<11;++j){
				if(num%a[j]==0){
					lis.push_back(j+1);
					if(!mp[j+1]) mp[j+1]=++tot;
					break;
				}
			}
		}
		printf("%d\n",tot);
		len = lis.size();
		for(int i=0;i<len;++i) printf("%d ",mp[lis[i]]);
		printf("\n");	
	}
}
int main(void)
{
	solve();
	return 0;
}

C.K-Complete Word

给定一个字符串,给定一个k,问最小替换次数使得该字符串为一个回文串且满足 s i = s k + i ( 1 ≤ i ≤ n − k ) si=sk+i (1≤i≤n−k) si=sk+i(1ink)

题解: 并查集
回文串就是 i i i n − i + 1 n-i+1 ni+1相连
s i = s k + i si=sk+i si=sk+i就是 i i i k + i k+i k+i相连
然后每个连通分量中取字母出现次数最大的那个为 m x mx mx,贡献为连通分量的大小 − - m x mx mx
每个连通分量贡献求和即可

#include
using namespace std;
typedef long long ll;
const int MAX = 2e5+5;
int t,n,k,ans;
char s[MAX];
int f[MAX],countt[MAX][26],fa[MAX],tot=0,cnt[MAX],FIND[MAX];
int find(int v){
	return f[v]==v?v:f[v]=find(f[v]);
}
void solve(){
	scanf("%d",&t);
	while(t--){
		ans=0,tot=0;
		scanf("%d%d%s",&n,&k,s+1);
		for(int i=1;i<=n;++i) f[i]=i,fa[i]=0,cnt[i]=0;
		for(int i=1;i<=k;++i) for(int j=0;j<26;++j) countt[i][j]=0;
		for(int i=1,j=n;i<=j;++i,--j) f[j]=i;
		for(int i=1;i<=k;i++){
			for(int j=i;j<=n-k;j+=k){
				int a = find(j),b = find(j+k);
				f[b]=a;
			}
		}
		for(int i=1;i<=n;++i) FIND[i]=find(i);
		for(int i=1;i<=n;++i){
			if(FIND[i]==i){
				fa[FIND[i]]=++tot;
			}
		}
		for(int i=1;i<=n;++i){
			cnt[fa[FIND[i]]]++;
			int ff = FIND[i];
			countt[fa[ff]][s[i]-'a']++;
		}
		for(int i=1;i<=tot;++i){
			int mx=-1,sum=0;
			for(int j=0;j<26;++j) mx=max(mx,countt[i][j]),sum+=countt[i][j];
			ans+=cnt[i]-mx; 
		}
		printf("%d\n",ans);
	}
}
int main(void)
{
	solve();
	return 0;
}

D.Walk on Matrix

题目给出一个程序,求一个从 ( 1 , 1 ) (1,1) (1,1) ( n , m ) (n,m) (n,m)的路径,这条路径上所有点权值与值最大,但是该程序并不是最优的,让我们构造一个矩阵,使得最优解与题意相差k

题解:
题目中给出的程序是有问题的,因为当前较小的那个路径可能影响到后面的结果,所以并不能取当前最大的路径.
考虑一个 2 ∗ 3 2*3 23矩阵
I N F + k , k , 0 INF+k,k,0 INF+k,k,0
I N F , I N F + k , k INF,INF+k,k INF,INF+k,k
题意求得的解是 0 0 0,因为 ( 2 , 2 ) (2,2) (2,2)这个点选择的是 ( 2 , 1 ) (2,1) (2,1),到了 ( 2 , 3 ) (2,3) (2,3)一定是 0 0 0
但是 ( 2 , 2 ) (2,2) (2,2)明显可以选择更小的路径 ( 1 , 2 ) (1,2) (1,2),这样答案就是 k k k

#include 
using namespace std;
const int INF = 1<<17;
void solve(){
	int k;
	scanf("%d",&k);
	printf("%d %d\n",2,3);
	printf("%d %d %d\n",INF+k,k,0);
	printf("%d %d %d\n",INF,INF+k,k);
}
int main()
{
	solve();
    return 0;
}

E. Height All the Same

给定一个 n ∗ m n*m nm的网格图,每个网格上初始时都有 [ L , R ] [L,R] [L,R]范围数量大小的木块,现在你有两种操作,第一种是在一个网格中堆叠两个木块,第二种是在相邻的网格中堆叠一个木块,求有多少种初始时的方案使得经过有限次操作后所有网格的高度一样.

题解:
设定最后高度一样时的高度为 H H H, n u m ( i , j ) num(i,j) num(i,j)为初始时 ( i , j ) (i,j) (i,j)方格上的木块数.
那么需要加入的木块数为 c o u n t count count = n ∗ m ∗ H n*m*H nmH - ∑ \sum n u m ( i , j ) num(i,j) num(i,j).
首先明确一点,假如count为偶数,那么最后一定能使得高度一样,不论初始时形状如何.
讨论 n ∗ m n*m nm对于count的奇偶性的影响.
n ∗ m n*m nm为奇数时,很明显,不论 ∑ \sum n u m ( i , j ) num(i,j) num(i,j)奇偶如何,前面的 n ∗ m ∗ H n*m*H nmH都可奇可偶(因为H是可奇可偶的),即所有方案都是合法的.

n ∗ m n*m nm为偶数时. n ∗ m ∗ H n*m*H nmH一定为偶数,那么考虑 ∑ \sum n u m ( i , j ) num(i,j) num(i,j)这部分.
然后当R-L+1为奇数时, ∑ \sum n u m ( i , j ) num(i,j) num(i,j)为偶数的方案比为奇数的方案多1.因为永远都是多了一个每个网格都是R的那个情况.
先考虑 n = 1 , m = 2 , L = 1 , R = 4 n=1,m=2,L=1,R=4 n=1,m=2,L=1,R=4的情况,这个时候明显是奇偶情况参半的
假如现在把R改成5,那么就是在原来的基础上加了9种情况:
(5,1),(5,2),(5,3),(5,4) (第一个网格为5的情况)
(1,5),(2,5),(3,5),(4,5) (第二个网格为5的情况)
(5,5) (两个网格都为5的情况)
很明显多出了一种所有网格都为R的初始情况.特殊处理一下即可

#include
using namespace std;
typedef long long ll;
const ll mod = 998244353;
ll quick(ll a,ll n){
	ll ans=1;
	while(n>0){
		if(n&1){
			ans=ans*a%mod;
		}
		n>>=1;
		a=a*a%mod;
	}
	return ans;
}
void solve(){
	ll n,m,L,R;
	scanf("%lld%lld%lld%lld",&n,&m,&L,&R);
	if(n*m%2!=0) printf("%lld\n",quick(R-L+1,n*m));
	else if(R-L+1&1) printf("%lld\n",((quick(R-L+1,n*m)+1)*quick(2ll,mod-2))%mod);
	else printf("%lld\n",((quick(R-L+1,n*m))*quick(2ll,mod-2))%mod);
}
int main(void)
{
	solve();
	return 0;
}

你可能感兴趣的:(codeforces题解)