Codeforces Round 870 (Div. 2)(A--D)

A. Trust Nobody

1、问题

A. Trust Nobody

2、分析

因为 n n n的很小,所以直接枚举说谎话的人数 k k k,然后遍历数组,统计说话的人数是否和 k k k相同。如果相同直接输出,如果没有符合条件的,输出-1。

3、代码

#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
void solve()
{
	int n;
	cin >> n;
	vector<int>a(n);
	for(auto &x : a)
		cin >> x;
	bool flag = false;
	for(int i = 0; i < n; i ++)
	{
		int cnt = 0;
		for(int j = 0; j < n; j ++)
		{
			if(a[j] > i)
				cnt++;
		}
		if(cnt == i)
		{
			cout << cnt << endl;
			return;
		}
	}
	cout << -1 << endl;
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t--)
	solve();
}

B. Lunatic Never Content

1、问题

B. Lunatic Never Content

2、分析

假设首尾相对的两个元素是 a a a b b b
a   m o d   x = b   m o d   x a\ mod\ x = b\ mod\ x a mod x=b mod x
a   m o d   x − b   m o d   x = 0 a\ mod\ x-b\ mod\ x = 0 a mod xb mod x=0
( a − b )   m o d   x = 0 (a-b)\ mod\ x =0 (ab) mod x=0

我们的 x x x要是每一组 a b s ( a − b ) abs(a-b) abs(ab)的因子,我们又要保证最大值。即求所有差值绝对值的最大公因数

3、代码

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int N = 1e5 + 10;

void solve()
{
	int n;
	cin >> n;
	vector<int>a(n),b;

	for(int i = 0; i < n; i ++)
		cin >> a[i];

	for(int i = n - 1; i >= 0; i --)
		b.push_back(a[i]);

	if(a == b)
	{
		cout << 0 << endl;
		return;
	}
	
	int nums = -1;
	int l = 0, r = n - 1;
	while(l < r)
	{
		if(a[l] == a[r])
		{
			l ++ ,r --;
			continue;
		}
		if(nums == -1)
			nums = abs(a[l] - a[r]);
		else
			nums = __gcd(abs(a[l] - a[r]), nums);
		l ++ ,r --;
	}
	cout << nums << endl;
}

signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t--)
	solve();
}

C. Dreaming of Freedom

1、问题

C. Dreaming of Freedom

2、分析

先考虑特殊情况,如果 n n n m m m是1的话,那么必定可以投完。一种是算法只有一个,一种是人只有一个。

接下来讨论 n ≠ 1   & &   m ≠ 1 n\neq 1 \ \&\&\ m \neq 1 n=1 && m=1 的情况。

如果 n ≤ m n \leq m nm

我们只需要在第一投票的时候一人投一个算法,此时所有的算法中,就会出现 n n n个算法有1票, n − m n-m nm个算法有 0 0 0票。此时,就会舍弃这 n − m n-m nm个算法,只剩下 n n n个算法。接下来,我们继续保持这种策略,即一人投一个算法,这样就会导致这 n n n个算法的票数一直是一样的。即肯定投不完。

如果 n > m n>m n>m

假设 a a a n n n的一个因数,同时 1 < a < m 1<a<m 1<a<m,在这种情况下,我们可以让这 n n n个人只投 a a a个算法,同时由于整除的关系,这 n n n个算法中的每一个算法都能获得 n a \frac{n}{a} an票。该轮结束后,就会剩下这 a a a个,然后我们只需要继续重复上述策略,让每个算法都保持 n a \frac{n}{a} an票,无限循环下去。
总结一下,如果 n n n的因数小于 m m m,那么就会存在无限循环的情况。

如果上面的三种情况都不满足,则必定可以在有限次数内结束投票。

3、代码

#include<bits/stdc++.h>
#define endl '\n'
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 1e5 + 10;

void solve()
{
	int n, m;
	cin >> n >> m;

	if(m == 1 || n == 1)
	{
		cout << "YES" << endl;
		return;
	}
	if(n <= m)
	{
		cout << "NO" << endl;
		return;
	}
	for(int i = 2; i <= sqrt(n); i ++)
	{
		if(n % i == 0)
		{
			if(i <= m && i != 1)
			{
				cout << "NO" << endl;
				return;
			}
			if(n / i <= m && n / i != 1)
			{
				cout << "NO" << endl;
				return;
			}
		}
	}
	cout << "YES" << endl;

}

signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t--)
	solve();
}

D. Running Miles

1、问题

D. Running Miles

2、分析

我们先对式子变形。
b 1 + b 2 + b 3 − ( r − l ) b1+b2+b3-(r-l) b1+b2+b3(rl)
b 1 + b 2 + b 3 − r + l b1+b2+b3-r +l b1+b2+b3r+l
( b 1 + l ) + b 2 + ( b 3 − r ) (b1+l)+b2+(b3-r) (b1+l)+b2+(b3r)

现在我们可以构造三个数组,一个数组是 b i + i b_i+i bi+i,一个数组是 b i b_i bi,一个数组是 b i + i b_i+i bi+i

我们分别将这三个数组称为: A , B , C A,B,C A,B,C

我们只需要枚举每一个 B i B_i Bi,然后找到在 i i i之前的最大的 A i m a x A_{imax} Aimax,以及在 i i i之后的最大的 C i m a x C_{imax} Cimax,即可得到对于当前 B i B_i Bi而言,最优的选择。按照上述的套路去遍历每一个 B i B_i Bi,求出最优解,最后比较出一个最大值。

从上述的做法可以看出,我们最后枚举的区间是让两个最值分布在了区间的左右端点。为什么这样做就是对的呢?

我们先看左端点,如果我们的左端点所对的元素不是最值,就说明我们的 l l l还可以向右移动,此时 l l l就变大了,结果也会变大,直到恰好走到最值的位置。右侧的 r r r同理。

从这个证明可以看出,我们的左右端点一定要尽可能的向最值靠拢。

接着,我们还要证明一个事情:为什么上述做法能保证这三个数字是最大的前三个数。我们以左端点为例子,如果左端点不是最值,说明在左端点的右侧存在一个 k k k大于左端点,而 l k > l l_k>l lk>l,所以 k + l k k+l_k k+lk> A l A_l Al。所以我们的 A l A_l Al不是最大值,但是根据我们刚刚的套路,我们取的是 i i i前面的最大值。二者矛盾。所以端点一定是最值。

那么找最大值的过程可以利用前缀和与后缀和的思路去预处理出最大值。

3、代码

#include<bits/stdc++.h>
#define endl '\n'
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
const int N = 1e5 + 10;
void solve()
{
	int n;
	cin >> n;
	vector<int>a(n), b(n), c(n), B(n), C(n);
	for(int i = 0; i < n; i ++)
		cin >> a[i];
	for(int i = 0; i < n; i ++)
	{
		b[i] = a[i] + i;		
		if(!i)
			B[i] = b[i];
		else
			B[i] = max(B[i -  1], b[i]);
	}
	for(int i = n - 1; i >= 0; i --)
	{
		c[i] = a[i] - i;
		if(i == n - 1)
			C[i] = c[i];
		else
			C[i] = max(C[i + 1], c[i]);
	}
	int ans = -INF;
	for(int i = 1; i < n - 1; i ++)
	{
		ans = max(a[i] + B[i - 1] + C[i + 1], ans);
	}
	cout << ans << endl;
}

signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while(t--)
	solve();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值