Codeforces Round #630 (Div. 2)(A-D)

A 在一个方格可以多次,那么可以在相邻的两个方格来回走,然后会在左右或者的一个方向剩下几步,判断是否越边界就可以了,除此之外还要特判x1== x2或者y1== y2(刚才那样有一个前提条件,那个方向上得能迈出去,感谢样例)

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
typedef long long ll;
int t,a,b,c,d,x,y,x1,x2,y1,y2;
int main()
{
	cin>>t;
	while(t--)
	{
		cin>>a>>b>>c>>d>>x>>y>>x1>>y1>>x2>>y2;
		if(x==x1&&x1==x2&&(a||b))
		{
			puts("No");
			continue;
		}
		if(y==y1&&y==y2&&(c||d))
		{
			puts("No");
			continue;
		}
		if(a>=b) a=a-b,b=0;
		else b=b-a,a=0;
		if(c>=d) c=c-d,d=0;
		else d=d-c,c=0;
		if(x-x1>=a&&x2-x>=b&&y-y1>=c&&y2-y>=d) puts("Yes");
		else puts("No"); 
	}
	
	return 0;
  }  

B 相同颜色的数的gcd必须大于1,那么我们可以给有形同质因子的数全部染上相同的颜色,然后就分解质因子呗,第11个质因子是31,31*37>1000了,所以前11个质质数完全可以处理1000以内的所有合数。给每个出现的质数一个颜色,每个合数中选一个质因数染色

#include<bits/stdc++.h>
using namespace std;
const int N=100010;
typedef long long ll;
int t,n;
int a[N],c[N];
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		int num[10000]={0},m=1;//num标记质因数的颜色
		for(int i=1;i<=n;i++) 
		{
			scanf("%d",a+i);
			for(int j=2;j*j<=a[i];j++)//分解质因数
			{
				if(a[i]%j==0) 
				{
					if(num[j]) c[i]=num[j];
					else c[i]=num[j]=m++;
					break;
				}
				while(a[i]%j==0) a[i]/=j;
			}
		}
		printf("%d
",m-1);
		for(int i=1;i<=n;i++) printf("%d ",c[i]);
		puts("");
	}
	return 0;
  }  

C 根据定义si=s[k+i],那么就有
s1=s[1+k]=s[1+2k]…
sn=s[n-k]=s[n-2
k]…
然后还得是回文串 s1=sn,联立一下这些位置必须相等,找最多的字母次数,总的这些位置的数量减它就是这些位置的最小变化,其他位置一样,k是奇数还需要特判一下。

#include<bits/stdc++.h>
using namespace std;
const int N=200010;
typedef long long ll;
int t,n,k;
int a[N],c[N];
char s[N];
int main()
{
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d %d ",&n,&k);
		scanf("%s",s+1);
		int ans=0;
		for(int i=1;i<=(k+1)/2;i++)
		{
			int num[30]={0};//别忘了清0
			if((k&1)&&i==(k+1)/2)//这个时候的i和k-i+1相等,所以得特判
				for(int j=i;j<=n;j+=k) num[s[j]-'a']++;
			 else 
			 {
			 	for(int j=i;j<=n;j+=k) num[s[j]-'a']++;
			 	for(int j=k-i+1;j<=n;j+=k) num[s[j]-'a']++;
			 }
			 int sum=0,m=0;
			 for(int i=0;i<26;i++) m=max(num[i],m),sum+=num[i]; 
			 ans+=(sum-m);
		}
		printf("%d
",ans);
	}
	return 0;
  }  

D 他的错误dp是因为&过程中的最大值不一定能使后面的&操作最大
要使最优解与他输出的差值为k,感觉两个值分别等 k和0是比较好构造吧,所以我的目的是使最优解为k,而dp输出0,假设点[n,m]位置为k,为方便构造减少分支情况就把所有情况都从一个方向来,就令[n-1,m]为0,这个方向一定为0。
接下来就是使 dp[n][m-1]&k 等0,而[n,m-1]可以得到的较小的值&k等k,什么值&k等0呢,k按位取反(令他为m)。
然后看一下m的范围是3e5是不是一定比1e5范围的k大,3e5以内的数二进制最多有19位,而1e5以内最多有17位,所以k的18位上一定是0,那么m的18位就一定是1了,所以m一定大于k 。
所以就可构造[n-1,m-1]为m,[n,m-2]为k,令s=2^18-1(二进制下各位都是1,小于3e5的最大值,&任何数的结果都等原数),其他位所有数都为s,这样两行三列足矣,所以构造的矩阵就是 s m 0
k s k

#include<bits/stdc++.h>
using namespace std;
const int N=200010;
typedef long long ll;
int t,n,k,m,s;
int a[N],c[N];
char s[N];
int main()
{
		cin>>k;
		for(int i=0;i<20&&(m+(1<<i)<3e5);i++)
		{
			s+=(1<<i);
			if((k&(1<<i))==0&&m+(1<<i)<3e5)
				m+=(1<<i);
		}
		cout<<2<<' '<<3<<endl;
		cout<<s<<' '<<k<<' '<<0<<endl;
		cout<<m<<' '<<s<<' '<<k;
	return 0;
  }  

第一次过四题体验挺好hh,E太难了,溜了

原文地址:https://www.cnblogs.com/neflibata/p/12871767.html