Codeforces Round #846 (Div. 2) ABEF

37 篇文章 0 订阅
9 篇文章 0 订阅

题目链接:https://codeforces.com/contest/1780

A - Hayato and School

解题思路:组合就是要么三个都是奇数,要么一个奇数,否则就是NO。

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define lson l,mid,rt<<1
#define rson mid+1,r,(rt<<1)|1
typedef long long ll;
const int mx = 3e5 + 10;

int a[mx];
vector<int> v[2];

int main() {
	int t;
	scanf("%d", &t);
	while (t--) {
		int n;
		scanf("%d", &n);
		v[0].clear();
		v[1].clear();
		for (int i=1;i<=n;i++) {
			scanf("%d", a+i);
			v[a[i]%2].push_back(i);
		}
		if (v[1].size() > 2) {
			puts("YES");
			printf("%d %d %d\n", v[1][0], v[1][1], v[1][2]);
		} else if (v[1].size() && v[0].size() > 1){
			puts("YES");
			printf("%d %d %d\n", v[1][0], v[0][0], v[0][1]);
		} else
			puts("NO");
	}
	return 0;
}

B - GCD Partition

解题思路:肯定是分成2半gcd值最大,设总和是sum,那么第一部分和第二部分的gcd是和sum的gcd是一样的,因为肯定是公约数。所以只要看sum和哪个前缀和gcd大就行了。

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define lson l,mid,rt<<1
#define rson mid+1,r,(rt<<1)|1
typedef long long ll;
const int mx = 3e5 + 10;

int a[mx];
ll sum[mx];

int main() {
	int t;
	scanf("%d", &t);
	while (t--) {
		int n;
		scanf("%d", &n);
		for (int i=1;i<=n;i++) {
			scanf("%d", a+i);
			sum[i] = sum[i-1] + a[i];
		}
		ll ma = 0;
		for (int i=1;i<n;i++) {
			ma = max(ma, __gcd(sum[i], sum[n]));
		}
		printf("%lld\n", ma);
	}
	return 0;
}

E - Josuke and Complete Graph

解题思路:(1)首先可以得出任意两个数的gcd不会大于r-l,假设gcd(l, r) = x > r - l,l = x * i,r = x * j。因为l != r,所以i != j, i < j,所以x * j - x * i >= x > r - l,两者互相矛盾。(2)还可以证明任意两个数的gcd肯定不大于r / 2。(3)令x = (r - l + 1) / 2,那么肯定存在1-x的gcd。因为肯定存在 l <= i * x < (i + 1) * x <= r。二者gcd为x。

        另外一种通用的解求是否存在gcd有x,就有 l + 2 * x - l % x <= r,当l % x == 0时,式子为      l + x <= r。l + x - l % x就是求第一个能整除x的位置,l + 2 * x - l % x求第二能整除x的位置,二者gcd为x,因为二值肯定大于l,所以只要考虑小于等于r。从式子可知当x > l时,式子就为2 * x <= r。这个式子就很好求了。所以我们只要讨论x <= l的情况,因为l <= 1e9,并且我们是从(r - l + 1) / 2开始讨论的x,所以可以大概计算出,2 * l / (r - l + 1)  = y这个因数并不会特别大。因为             (r - l +1)大,y就小。r - l +1小,那么我们就根据(1)直接暴力即可。接下来就需要考虑如果暴力枚举y,讲上面式子改为l + 2 * x -  p <= r,令l = y * x + p。那么根据这个式子,x每+1,左边式子就要加y + 2,因为式子就会变成l + 2 * (x + 1) - p + y,令l + y * (x + 1) + p - y,因此在y相同的情况下,我们可以计算出有多少个x满足这个条件。然后去枚举每个y。直到y = 0,x > l为止。

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define lson l,mid,rt<<1
#define rson mid+1,r,(rt<<1)|1
typedef long long ll;
const int mx = 3e5 + 10;

int main() {
	int t;
	scanf("%d", &t);
	while (t--) {
		ll l, r;
		scanf("%lld%lld", &l, &r);
		ll ans = (r - l + 1) / 2;
		ll x = (r - l + 1) / 2 + 1;
		ll mi = min(l, r - l + 1);
		while (x <= mi) {
			ll m = l % x;
			if (l % x == 0)
				m = x;
			ll left = l / x;
			if (x * 2 <= r - l + m) {
				ll temp = m / left;
				if (m == x)
					temp = 0;
				if (m % left == 0)
					temp = max(temp - 1, 0ll);
				ll v1 = r - l + m - x * 2;
				ll v2 = min(v1 / (left + 2), temp);
				ans += v2 + 1;
				x += temp;
			}
			x++;	
		}
		ans += max(0ll, min(r/2, r - l + 1) - x + 1);
		printf("%lld\n", ans);
	}
	return 0;
}

F - Three Chairs

解题思路:先排个序,然后可以知道一个数最多的不同质因子个数是6。我们可以通过容斥法来减去前面有和当前位置相同质因子的值。就是每个位置当最大的数量了。时间复杂为O(n\sqrt{n} + 2^{6}n)

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define lson l,mid,rt<<1
#define rson mid+1,r,(rt<<1)|1
typedef long long ll;
const int mx = 3e5 + 10;

int a[mx];
bool vis[mx];
vector <int> pri;
pair <ll, int> val[mx];

void init()
{
	for (int i=2;i<mx;i++) {
		if (!vis[i]) {
			pri.push_back(i);
		}
		for (int v: pri) {
			if (v * i >= mx)
				break;
			vis[i * v] = 1;
			if (i % v == 0)
			    break;
		}
	}
}

ll solve(vector<int> &tv, int idx, int vs, int fg, int ps) {
	ll ans = fg * (1ll * val[vs].second * (ps - 1) - val[vs].first);
	for (int i=idx; i<tv.size(); i++) {
		ans += solve(tv, i + 1, vs * tv[i], -fg, ps);
		val[vs * tv[i]].first += ps;
		val[vs * tv[i]].second++;
	}
	return ans;
}

int main() {
	init();
	int n;
	scanf("%d", &n);
	for (int i=1;i<=n;i++) {
		scanf("%d", a+i);
	}
	ll ans = 0, sum = 0;
	sort(a + 1, a + 1 + n);
	for (int i=1;i<=n;i++) {
		vector <int> tv;
		for (int v: pri) {
			if (v * v > a[i])
				break;
			if (a[i] % v == 0) {
				tv.push_back(v);
				a[i] /= v;
				while(a[i] % v == 0)
					a[i] /= v;
			}
		}
		if (a[i] != 1) tv.push_back(a[i]);
		ans += sum - i + 1;
		ans += solve(tv, 0, 1, 1, i);
		sum += i;
	}
	printf("%lld\n", ans);
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值