模拟赛2

1.魔法阵


解题思路

由于要求删除后仍然是一个正多边形,这就保证剩余的点数一定是n的因子,只有这样才能均匀删除
所以我们只需要枚举n的因子作为剩余多边形的顶点数,对答案取max即可
时间复杂度为O(nlogn)

AC代码

#include<cstdio>
#include<algorithm>
using namespace std;
int n,s,answer,a[20005];
int main()
{
   
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
   
		scanf("%d",&a[i]);
		s+=a[i];//不删除
	}
	int answer=-2147483647;//初值
	for(int i=1;i<=n;i++)//枚举约数
	 if(n%i==0&&n/i>=3)
	  for(int j=0;j<i;j++)//每个约数中再枚举初始点
	  {
   
	  	int ans=0;
	  	for(int k=j;k<=n;k+=i)ans+=a[k];//累加
	 	answer=max(answer,ans);//求max 
	  }
	printf("%d",max(s,answer)); 
	return 0;	
} 

2.小biu放牛



注意:“输出格式”中的“码头”是“农场”

解题思路

首先由于要求最大值最小,最先想到的应该是二分+检查正确性
这样我们就知道最长绳子的长度,于是我们选择从左到右贪心的去放置每一头牛
假设我们已经放置X头牛,那么如果第X+1头牛紧贴在第X头牛放置是合法的,那么则紧贴着放

否则我们检查一下第X头牛能放置的最左位置,把它放置在能放置的最左位置即可
当出现某个木桩在第X头牛的左侧,而且如果要在绳子长度内放置下一头牛,下一头牛和当前牛重叠,则说明不合法
如果最终总长度超过M,也说明不合法,否则都是合法的情况
时间复杂度为O(nlogn)

注意:绳子长度可以为0

AC代码

#include<algorithm>
#include<cstdio>
#include<cmath>
using namespace std;
int n,x,m,l,r,a[50005];
bool check(int xmid)//检查正确性
{
   
	int beg=0,end=0;//beg为牛头位置,end为牛尾位置
	for(int i=1;i<=n;i++)
	{
   
		beg=max(end,a[i]-xmid-x);//找最靠左的牛头的位置
		if(abs(beg-a[i]+x)>xmid)return true;//判断绳子长度是否超过xmid
		end=beg+2*x;//尾
		if(end>m)return true;
	}
	return false;
}
int main()
{
   
	scanf("%d%d%d",&n,&x,&m);
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	r=m;//初值
	while(l<=r)//二分
	{
   
		int mid=(l+r)/2;
		if(check(mid))l=mid+1;
		else r=mid-1;
	}
	if(l>m)printf("-1");//输出
	else printf("%d",l);
	return 0;
}

3.小A的游戏


解题思路

考虑如果出现两个相同字符之间的距离小于等于k时,小A一定可以删除这连续的一段,让小B无法判断他删除的是前面的字符还是后面的字符,否则则小B一定能判断
所以当且仅当出现两个相同字符之间的距离小于等于k时,答案为Uncertain,否则答案为Certain

注意:可能全删掉,就是“Certain”

AC代码

#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
int t,k,last[26];
string s;
int main()
{
   
	scanf("%d",&t);
	while(t)
	{
   
		t--;
		cin>>s;
		scanf("%d",&k);
		int l=s.size();//长度
		if(l==k)printf("Certain\n"); //特判,全删掉 
		else 
		{
   
			int ok=1;//初值
			memset(last,-1,sizeof(last));//初值
			for(int i=0;i<l;i++)//核心思路
			{
   
				int j=s[i]-'a';
				if(last[j]!=-1&&i-last[j]<=k){
   ok=0;printf("Uncertain\n");break;}//看两个相同字母的距离
				last[j]=i;
			}
			if(ok)printf("Certain\n"); //其他情况
		}
	}
	return 0;
}

4.小Biu闯关


解题思路

因为根据推理我们可以得出:
[a,b]可以表示[2a,2b],[3a,3b],[4a,4b]……[ka,kb]
长度分别为2b-2a+1,3b-3a+1,4b-4a+1……kb-ka+1
当kA<=(k-1)B时,区间就发生重合,之后的数就全部都能凑出来
于是,我们可以暴力求k,顺便求结果
核心

if(nextl<=r)//判断是否重叠
{
   
	ans+=(Y-max(X,l)+1);//求出结果
	break;
}
else ans+=(min(Y,r)-max(X,l)+1);//累加不能表达数的个数

但是,我们要考虑k的初始值
假如样例为这样
1
3 3 10 10
按照我的思路
设k的初始值为1
到ans+=(min(Y,r)-max(X,l)+1)这一步时就会累加负数
所以k要初值

if(B<X)i=X/B+1;//初值

就OK了

AC代码

#include<cstdio>
#include<algorithm>
using namespace std;
long long t,A,B,X,Y;
int main()
{
   
	scanf("%lld",&t);
	while(t)
	{
   
		t--;
		scanf("%lld%lld%lld%lld",&A,&B,&X,&Y);
		long long i=1,ans=0;//初值
		if(B<X)i=X/B+1;//初值
		while(1)
		{
   
			long long l=i*A,r=i*B,nextl=(i+1)*A;//方便后面
			if(l>Y)break;//如果l大于要表示最大的数Y,就退出
			if(nextl<=r)//判断是否重叠
			{
   
				ans+=(Y-max(X,l)+1);//求出结果
				break;
			}
			else ans+=(min(Y,r)-max(X,l)+1);//累加结果
			i++;
		}
		printf("%lld\n",ans);
	}
	return 0;
}

总结

分数
预估:10+100+20+10=140
实际:27+5+0+0=32
第二题二分l和r的初值没赋值好
其他题有点不会

谢谢