比赛记录:Codeforces Round 870 (Div. 2) A~D

传送门:CF

A题:A. Trust Nobody

观察到 n n n很小,所以可以直接枚举说谎者的数量,显然说谎者的数量不会超过 n n n,确定了一个假设出来的说谎者数量之后然后枚举每一个人是不是说谎即可,然后再判断一下这个和我们假设出来的人是否一致即可

#include 
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
	ll x=0,w=1;char ch=getchar();
	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}
#define maxn 1000000
const double eps=1e-8;
#define	int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int a[maxn];
int main() {
	int T=read();
	while(T--) {
		int n=read();
		for(int i=1;i<=n;i++) {
			a[i]=read();
		}
		int flag=0;
		for(int i=0;i<=n;i++) {
			int cnt=0;
			for(int j=1;j<=n;j++) {
				if(i<a[j]) {
					cnt++;
				}
			}
			if(cnt==i) {
				cout<<i<<endl;
				flag=1;
				break;
			}
		}
		if(flag==0) cout<<-1<<endl;
	}
	return 0;
}

B题:Lunatic Never Content

首先判断一下无穷的情况.我们会发现如果模数取无穷的话,我们新的数列肯定等于原数列,也就是如果原数列是回文数列的话,我们就可以取到无穷.所以特判一下
然后考虑如何使其变成回文数列.考虑同时枚举左右两端的数字.假设 a [ l ] = a [ r ] a[l]=a[r] a[l]=a[r],此时显然我们的 x x x取任意值都是满足条件的.假设此时 a [ l ] ! = a [ r ] a[l]!=a[r] a[l]!=a[r],我们假设存在一个 x x x能满足题意.那么有
a [ l ]    m o d    x = a [ r ]    m o d    x a[l]\;mod\;x=a[r]\;mod\;x a[l]modx=a[r]modx根据模运算,我们可以化解为 ( a [ l ] − a [ r ] ) m o d    x = 0 (a[l]-a[r])mod\;x=0 (a[l]a[r])modx=0,也就是说,只要此时我们的x取差的一个因数即可.那么对于最终我们的x显然就是取所有的 a b s ( a [ l i ] − a [ r i ] ) abs(a[l_i]-a[r_i]) abs(a[li]a[ri])的最大公约数即可.

#include 
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
	ll x=0,w=1;char ch=getchar();
	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}
#define int long long
#define maxn 1000000
const double eps=1e-8;
#define	int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int a[maxn];int n;
int check() {
	int l=1,r=n;
	while(l<=r) {
		if(a[l]!=a[r]) return false;
		l++;r--;
	}
	return true;
}
int gcd(int a,int b) {
	if(a%b==0) return b;
	else return gcd(b,a%b);
}
signed main() {
	int T=read();
	while(T--) {
		n=read();
		for(int i=1;i<=n;i++) a[i]=read();
		if(check()) {
			cout<<0<<endl;
			continue;
		}
		int l=1,r=n;int x=-1;
		while(l<r) {
			if(a[l]==a[r]) {
				l++;r--;
			}
			else {
				if(x==-1) x=abs(a[l]-a[r]);
				else x=gcd(abs(a[l]-a[r]),x);
				l++;r--;
			}
		}
		cout<<x<<endl;
	}
	return 0;
}

C题:Dreaming of Freedom

一道找规律题.首先应该特判掉 n = 1 , m = 1 n=1,m=1 n=1,m=1的情况
然后观察,当我们的 n < = m n<=m n<=m的时候,显然我们每一个人都可以选择一个不同的投票选项,那么我们会得到n个得到1票的情况,此时永远都是平局.所以直接输出"NO"
然后当n>m的时候.我们想要永远不会到1选项的情况,那么我们需要尽量的将所有人的票数平均,然后我们会发现只要存在一个(x<=m),使得 n % x = 0 n\%x=0 n%x=0的时候,显然我们可以直接选择只保留x个投票点,然后平均的投x即可.这样我们就可以保证永远会形成平局.
接下来讲一下为什么不存在(x<=m)就不可能形成平均.很显然,假设不存在一个因子,那么我们的投票点只会越来越少(记为k),要知道,只有存在因子我们才会形成平局,当我们的投票点处于最大的 m m m时还不存在因子,那么当我们的k越来越小(小于m)时因子的选择只会越来越少,就更加不可能存在因子了

#include 
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
	ll x=0,w=1;char ch=getchar();
	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}
#define maxn 1000000
const double eps=1e-8;
#define	int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int main() {
	int T=read();
	while(T--) {
		int n=read(),m=read();
		if(m==1||n==1){
			cout<<"YES"<<endl;
			continue;
		} 
		if(n<=m) {
			cout<<"NO"<<endl;
			continue;
		} 
		int flag=0;
		for(int i=2;i<=__builtin_sqrt(n)&&i<=m;i++) {
			if(n%i==0) {
				cout<<"NO"<<endl;
				flag=1;
				break;
			}
		}
		if(flag==0) {
			cout<<"YES"<<endl;
		}
	}
	return 0;
}

D题:D. Running Miles

一道诈骗题!!
题目很简单,就是求出一个区间的最大的三个值然后减去区间长度最大. b i 1 + b i 2 + b i 3 − ( r − l ) b_{i1}+b_{i2}+b_{i3}−(r−l) bi1+bi2+bi3(rl)
但是我们如果只关注到 ( r − l ) (r-l) (rl)是区间长度的话这道题将很难解出来.我们需要换一种想法.
不妨设 b 1 b1 b1为位置靠左的较大值, b 2 b2 b2为中间最大值, b 3 b3 b3为位置靠右最大值.根据表达式,显然区间长度越小越好,所以我们此时的 l l l显然取 b 1 b1 b1的位置, r r r b 3 b3 b3的位置.观察到 l l l只和 b 1 b1 b1的位置有关, r r r只和 b 3 b3 b3的位置有关,所以我们可以将 b 1 b1 b1 l l l绑定在一起.将 b 3 b3 b3 r r r绑定在一起.我们就有 ( b 1 + l ) + b 2 + ( b 3 − r ) (b1+l)+b2+(b3-r) (b1+l)+b2+(b3r),然后考虑分别求出三个部分的最大值(这样做的正确性是三个部分都是互不干扰的,可以想想为什么?).考虑将所有的b都一起加上一个当前的下标,然后记录一下前缀最大值.那么当我们枚举 b 2 b2 b2的时候,我们取一下 b 2 b2 b2之前的所有 b i + i bi+i bi+i的最大值即可.可能有人会有疑问,我们此时 b i + i bi+i bi+i的最大值有没有一种可能 b i bi bi并不是区间较大的值呢.
现在简单证明一下这个.假设我们存在 b k bk bk b 1 b1 b1要大,并且此时 b 1 b1 b1是左端点,所以此时 k > p o s ( b 1 ) k>pos(b1) k>pos(b1),所以显然此时 b k + p o s ( b k ) > b 1 + p o s ( b 1 ) bk+pos(bk)>b1+pos(b1) bk+pos(bk)>b1+pos(b1),与我们的前题矛盾.所以此时我们的整体最大值中的 b i bi bi就是区间较大值.
b 3 − r b3-r b3r部分的解决方法类似,我们用同样的方法记录一下后缀最大值即可.然后枚举中间值,对于所有情况,取一个 m a x max max即可

#include 
using namespace std;
typedef long long ll;
#define root 1,n,1
#define ls rt<<1
#define rs rt<<1|1
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
inline ll read() {
	ll x=0,w=1;char ch=getchar();
	for(;ch>'9'||ch<'0';ch=getchar()) if(ch=='-') w=-1;
	for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
	return x*w;
}
#define maxn 1000000
const double eps=1e-8;
#define	int_INF 0x3f3f3f3f
#define ll_INF 0x3f3f3f3f3f3f3f3f
int b[maxn];int c[maxn],d[maxn],lmax[maxn],rmax[maxn];
int main() {
	int T=read();
	while(T--) {
		int n=read();
		for(int i=1;i<=n+1;i++) {
			lmax[i]=rmax[i]=0;
		}
		for(int i=1;i<=n;i++) b[i]=read();
		for(int i=1;i<=n;i++) {
			c[i]=b[i]+i;
			d[i]=b[i]-i;
			if(i==1) lmax[i]=c[i];
			else lmax[i]=max(lmax[i-1],c[i]);
		}
		for(int i=n;i>=1;i--) {
			if(i==n) rmax[i]=d[i];
			else rmax[i]=max(rmax[i+1],d[i]);
		}
		int ans=-int_INF;
		for(int i=2;i<=n-1;i++) {
			ans=max(ans,b[i]+lmax[i-1]+rmax[i+1]);
		}
		cout<<ans<<endl;
	}
	return 0;
}

你可能感兴趣的:(c++算法,#,各类比赛,c++,算法)