2020牛客暑期多校训练营(第四场)

B-Basic Gcd Problem

题意:给c和x 求下面这个表达式的值

image-20200720235955011

思路:画一画可以得出公式是 c x 的 质 因 数 个 数 c^{x的质因数个数} cx ,用线性筛和快速幂来做。

#include <bits/stdc++.h>
using namespace std;

const int N = 1000000, mod = 1e9+7;
int _, n, c, isnot[N+6];
int gcr[N+6];

void getys(){
	for(int i=2;i <= N;i++){
		if(!isnot[i]) {
			for (int j = i; j <= N; j += i) {
				isnot[j] = true;
				int t = j;
				while(t%i==0) {t /= i; gcr[j]++;}
			}
		}
	}
}

long long qpow(long long x, long long n) { 
	long long res = 1; 
	for (; n; n >>= 1, x = x * x % mod) 
		if (n & 1) res = res * x % mod; 
	return res; 
}

int main() {
	getys(); 
	scanf("%d", &_);
	while(_--) {
		scanf("%d %d", &n, &c);
		printf("%lld\n", qpow(c, gcr[n]));
	}
}

F-Finding the Order

题意:给出四个点,AB在一条线上,CD在一条线上。给出AC,AD,BC,BD 的距离,求出是点 CD 的顺序是 “CD” 还是 “DC”

思路:把这些线连接起来看一下有什么特点,可以发现四条线组成了两个三角形。如下图所示,AD与BC形成的是两个三角形的的两两条边,AC与BD构成两个三条边的斜边,根据三角形的边的性质。就可以得出答案了。

image-20200720220031453

#include <bits/stdc++.h>
using namespace std;

int _, a, b, c, d;

int main() {
	scanf("%d", &_);
	while(_--) {
		scanf("%d %d %d %d", &a, &b, &c, &d);
		if(b+c>a+d) puts("AB//CD");
		else puts("AB//DC");
	}
}

H-Harder Gcd Problem

题意:在 ( 1 , 2 , 3 , . . . , n ) (1,2,3,...,n) (1,2,3,...,n) 中找到大小为m的两个子集,这两个子集对应的点的最大公因数 > 1 > 1 >1 ,求m和具体的子集。

思路:从 n 2 \frac{n}{2} 2n 开始预处理,找到 [ 1 , n 2 ] [1,\frac{n}{2}] [1,2n] 这里面的素数的所有的倍数,存起来,然后遍历每一个这里面的素数,让他们两两一对;如果出现有奇数的情况那么将这里面是偶数的数添加进入2的倍数里面就可以把浪费减小到最小。

拿22来举例看一下:

11 22
7 14 21
5 10 15 20
3 6 9 12 18
2 4 8 16

这个就是预处理的22以内的素数的所有倍数(重复的数只出现一次),然后我们开始更新答案

第一行 11 , 22 11, 22 11,22 可以

第二行有三个数,选择 7 , 21 7,21 7,21 , 将为偶数的14加入2的那一行,更新为:

11 22
7 21
5 10 15 20
3 6 9 12 18
2 4 8 16 14

第三行四个数都可以加入答案

第四行多出一个数,将6加入2那一行,更新为

11 22
7 21
5 10 15 20
3 9 12 18
2 4 8 16 14 6

然后第五行六个数都可以,所以答案为9

#include <bits/stdc++.h>
using namespace std;

int _, n;
const int M = 200005;
vector <int> g[M];
vector <pair<int, int> > ans;
bool isprime[M], vis[M];
void solve() {
	for(int i = 1;i <= M; i++) isprime[i] = 1;
	for(int i = 3;i <= M; i++) if(!(i%2)) isprime[i] = 0;
	for(int i = 2;i <= M; i++) {
		if(isprime[i]) {
			for(int j = i*2; j<= M; j += i)
				isprime[j] = 0;
		}
	}
	isprime[1] = 0;
}

int main() {
	solve();
	scanf("%d", &_);
	while(_--) {
		scanf("%d", &n);
		ans.clear();
		for(int i = 1;i <= n; i++) g[i].clear(), vis[i] = 0;
		int num = 0;
		for(int i = 2;i <= n/2; i++) {
			if(isprime[i]) {
				for(int j = i;j <= n; j+=i) {
					g[num].push_back(j);
				}
				num++;
			}
		}
		
		vector <int> t, nic;
		for(int i = num-1;i >= 0; i--) {
			t.clear(); nic.clear();
			for(auto j: g[i]) {
				if(vis[j]) continue;
				vis[j] = 1;
				t.push_back(j);
			}
			
			if(t.size()%2==0) nic = t;
			else {
				bool ok = 0;
				for(auto j: t) {
					if(!ok && j%2==0) ok = 1, vis[j] = 0;
					else nic.push_back(j);
				}
			}
			for(int j = 1;j < nic.size(); j += 2) {
				ans.push_back(make_pair(nic[j-1], nic[j]));
			}
		}
		
		printf("%d\n", (int)ans.size());
		for(auto i: ans) {
			printf("%d %d\n", i.first, i.second);
		}
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值