2020牛客暑期多校训练营(第四场)
比赛地址:
擦,这就第四场了,前几场题目还没补QAQ,这几天赶快补一下。
B Basic Gcd Problem
题目地址:
基本思路:
这题我们理解题意其实就比较简单了,
关键是要弄清楚题目中给出的这串式子的实际意义,
其实我们稍微分析其实就能发现,这个要找到后面的最大值,
其实就是找这个,不断的和其他数
变为
要的最大次数,然后这个最大值就是
;
然后变为
要的最大次数,这个我们根据唯一分解定理,就能知道如果每次我只
掉
的一个质因子,显然这样次数最多,那么质因子的个数就是这个最大次数了。
所以整理一下,就是求质因子的个数,然后
就是答案,预先筛一下素数,就能很快的质因数分解了;
参考代码:
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
#define IO std::ios::sync_with_stdio(false); cin.tie(0)
#define int long long
#define rep(i, l, r) for (int i = l; i <= r; i++)
#define per(i, l, r) for (int i = l; i >= r; i--)
#define mset(s, _) memset(s, _, sizeof(s))
#define pb push_back
#define pii pair <int, int>
#define mp(a, b) make_pair(a, b)
#define INF (int)1e18
inline int read() {
int x = 0, neg = 1; char op = getchar();
while (!isdigit(op)) { if (op == '-') neg = -1; op = getchar(); }
while (isdigit(op)) { x = 10 * x + op - '0'; op = getchar(); }
return neg * x;
}
inline void print(int x) {
if (x < 0) { putchar('-'); x = -x; }
if (x >= 10) print(x / 10);
putchar(x % 10 + '0');
}
const int mod = 1e9 + 7;
int qpow(int a, int b) {
int res = 1;
while (b > 0) {
if (b & 1) res = 1ll * res * a % mod;
a = 1ll * a * a % mod;
b >>= 1;
}
return res;
}
const int maxn = 1e6 + 10;
int prime[maxn];
bool is_prime[maxn];
int sieve(int n) {
int p = 0;
for (int i = 0; i <= n; i++) is_prime[i] = true;
is_prime[0] = is_prime[1] = false;
for (int i = 2; i <= n; i++) {
if (is_prime[i]) {
prime[p++] = i;
for (int j = 2 * i; j <= n; j += i) is_prime[j] = false;
}
}
return p;
}
int num;
map<int,int> prime_factor(int n) {
map<int, int> res;
for (int i = 0; prime[i] * prime[i] <= n && i < num; i++) {
while (n % prime[i] == 0) {
++res[prime[i]];
n /= prime[i];
}
}
if (n != 1) res[n] = 1;
return res;
}
int n,c;
signed main() {
IO;
num = sieve(1000010);
int t;
cin >> t;
while (t--) {
cin >> n >> c;
map<int, int> res = prime_factor(n);
int cnt = 0;
for(auto it : res) cnt += it.second;
int ans = qpow(c,cnt);
cout << ans << '\n';
}
return 0;
}H Harder Gcd Problem
题目地址:
基本题意:
感觉题面写的复杂了,其实就是让我们在范围那尽量多的挑选两两
不为
的数对,并且
内每个数只能用一次。
基本思路:
我们考虑想一种构造方法,能构造出最多的这个数对。
首先我们是肯定不能用的,首先排除,
然后我们知道大于的质数,肯定也找不出一个大于它小于
又不和它互质的数,
所以我们只要对范围内的每个质数考虑构造方法,
这里我们先将留下后面再使用,然后枚举
范围内的每个质数,
对于每个质数,我们先留
不用,在
范围内找还未使用的
,
然后我们可以反向枚举(不反向也可以,只是留方便一点)将这些未使用的
两两匹配成一个答案数对,
但是如果是奇数,由于反向枚举那么两两匹配就会剩下,所以这时再将
和前面预留的
配对。
最后,我们知道上述过程中的们有些被使用了,而有些却没有,但他们都是
的倍数,
所以我们之前预留的又有用了,我们再将
的倍数里未被使用的部分两两匹配。
比较容易发现这种贪心构造思路能构造出最多数对。
参考代码:
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
#define IO std::ios::sync_with_stdio(false); cin.tie(0)
#define int long long
#define rep(i, l, r) for (int i = l; i <= r; i++)
#define per(i, l, r) for (int i = l; i >= r; i--)
#define mset(s, _) memset(s, _, sizeof(s))
#define pb push_back
#define pii pair <int, int>
#define mp(a, b) make_pair(a, b)
#define INF (int)1e18
inline int read() {
int x = 0, neg = 1; char op = getchar();
while (!isdigit(op)) { if (op == '-') neg = -1; op = getchar(); }
while (isdigit(op)) { x = 10 * x + op - '0'; op = getchar(); }
return neg * x;
}
inline void print(int x) {
if (x < 0) { putchar('-'); x = -x; }
if (x >= 10) print(x / 10);
putchar(x % 10 + '0');
}
const int maxn = 2e5 + 10;
int a[maxn];
bool vis[maxn], b[maxn];
signed main() {
int t;
cin >> t;
for (int i = 2; i < maxn; i++) { // 素数筛;
if (vis[i]) continue;
for (int j = 2 * i; j < maxn; j += i) vis[j] = true;
}
while (t--) {
int n;
cin >> n;
for (int i = 1; i <= n; i++) b[i] = false;
vector<pii > ans;
for (int i = n / 2; i > 2; i--) { //找[3,n/2]范围内的所有质数p;
if (!vis[i]) {
int c = 0, j;
for (j = i; j <= n; j += i) {
if (j == 2ll * i) continue; //留一个2p给奇数个剩下那个;
if (!b[j]) a[++c] = j;
}
for (j = c; j > 1; j -= 2) { //将p,3p,4p,5p...kp<=n里没使用过的都两两匹配;
ans.emplace_back(mp(a[j], a[j - 1])), b[a[j]] = b[a[j - 1]] = true;
}
//奇数个就会剩下p和2p匹配;
if (j == 1) ans.emplace_back(mp(a[j] * 2, a[j])), b[a[j] * 2] = b[a[j]] = true;
}
}
int c = 0;
//把剩下没匹配的2p也两两匹配;
for (int j = 2; j <= n; j += 2) if (!b[j]) a[++c] = j;
for (int j = c; j > 1; j -= 2) ans.emplace_back(mp(a[j], a[j - 1])), b[a[j]] = b[a[j - 1]] = true;
cout << ans.size() << endl;
for (auto it : ans)
cout << it.first << ' ' << it.second << endl;
}
return 0;
}F Finding the Order
题目地址:
基本思路:
比赛时疯狂分类讨论,然而我们其实比较容易证明,梯形的对角线之和必定大于两腰之和。
因此如果 那么就是
否则
。
ps.证明可见百度知道:https://zhidao.baidu.com/question/196726920.html
参考代码:
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
using namespace std;
#define IO std::ios::sync_with_stdio(false); cin.tie(0)
#define int long long
#define rep(i, l, r) for (int i = l; i <= r; i++)
#define per(i, l, r) for (int i = l; i >= r; i--)
#define mset(s, _) memset(s, _, sizeof(s))
#define pb push_back
#define pii pair <int, int>
#define mp(a, b) make_pair(a, b)
#define INF (int)1e18
inline int read() {
int x = 0, neg = 1; char op = getchar();
while (!isdigit(op)) { if (op == '-') neg = -1; op = getchar(); }
while (isdigit(op)) { x = 10 * x + op - '0'; op = getchar(); }
return neg * x;
}
inline void print(int x) {
if (x < 0) { putchar('-'); x = -x; }
if (x >= 10) print(x / 10);
putchar(x % 10 + '0');
}
int a,b,c,d;
signed main() {
IO;
int t;
cin >> t;
while (t--) {
cin >> a >> b >> c >> d;
if(a + d < b + c) cout << "AB//CD" << '\n';
else cout << "AB//DC" << '\n';
}
return 0;
}
京公网安备 11010502036488号