A. Exponential Equation
![](https://img-blog.csdnimg.cn/img_convert/7b1200c7f4c362609e7658341235d403.png)
给出一个数n,给出一组x和y满足,若不存在满足情况的一组x和y,输出-1。
思路:一般这样的题向特殊情况思考。两数一个1,一个n/2即可满足,但是此时n必须为偶数;样例中奇数都是-1,则大胆猜测奇数输出-1即可。
AC Code:
#include <bits/stdc++.h>
typedef long long ll;
#define INF 0x3f3f3f3f
const int N = 2e5 + 5;
int t, n;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin >> t;
while(t --) {
std::cin >> n;
if(n & 1)
std::cout << -1 << '\n';
else
std::cout << 1 << ' ' << n / 2 << '\n';
}
return 0;
}
B. Number Factorization
![](https://img-blog.csdnimg.cn/img_convert/1f65f7fa70e56bf84891d97d8967f152.png)
给出一个数n,可以将它分解成如题的一串数字相乘,得到两个序列a和p,求分解后每个a[i] * p[i]和的最大值,底数根据唯一分解定理所有因子的幂次必须都是1。
思路:因为是加法,所以每个底数越大越好,所以可以将n质因数分解,贪心计算每个数的值,相加即可。
AC Code:
#include <bits/stdc++.h>
typedef long long ll;
const int N = 2e5 + 5;
int t, n, tot;
int prime[N], dif[N];
bool mark[N];
void oula() {
for(int i = 2; i <= N; i ++) {
if(!mark[i])
prime[++ tot] = i;
for(int j = 1; j <= tot; j ++) {
if(i * prime[j] > N)
break;
mark[i * prime[j]] = 1;
if(i % prime[j] == 0)
break;
}
}
}
struct node {
int prime, cnt;
bool operator < (const node & a) const {
return cnt < a.cnt;
}
};
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin >> t;
oula();
while(t --) {
std::cin >> n;
std::map<int, int> mp;
for(int i = 1; i <= tot; i ++) {
while(n % prime[i] == 0) {
mp[prime[i]] ++;
n /= prime[i];
}
}
if(n != 1)
mp[n] ++;
std::vector<node> vec;
for(auto [x, y] : mp) {
node b = {x, y};
vec.push_back(b);
}
vec.push_back({1, 0});
std::sort(vec.begin(), vec.end());
int len = vec.size();
dif[0] = 1;
for(int i = 1; i < len; i ++) {
dif[i] = dif[i - 1] * vec[i].prime;
}
ll ans = 0;
for(int i = len - 1; i >= 1; i --) {
vec[i].cnt -= vec[i - 1].cnt;
ans += vec[i].cnt * (dif[len - 1] / dif[i - 1]);
}
std::cout << ans << '\n';
}
return 0;
}
C. Remove the Bracket
![](https://img-blog.csdnimg.cn/img_convert/e9ae5ea17fbe2f3aab44e45ef8f0b2b1.png)
给出一个数组a,将从a[2] ~ a[n - 1]每一个分解为x[i] + y[i] = a[i],且(x[i] - s) * (y[i] - s) >= 0,求F的最小值。
思路:对于每一个a[i]来说,分解成的x[i]和y[i]仅在y[i - 1] * x[i] + y[i] * x[i + 1]这一部分中使用,可以换算成y[i - 1] * x[i] + (a[i] - x[i)] * x[i + 1],这样就是一个关于x[i]的一元一次函数,在极值处取得最小值,对于a[i] >= s,x[i]可以取到a[i] - s ~ s;反之,则取到0 ~ a[i]之间。设置f[i][4]表示前i个数的分解,4表示上一个数使得y[i]取值分别为0,s,a[i] - s,s,然后进行转移。
AC Code:
#include <bits/stdc++.h>
typedef long long ll;
const int N = 2e5 + 5;
int t, n, s;
ll a[N];
ll f[N][4];
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin >> t;
while(t --) {
std::cin >> n >> s;
for(int i = 1; i <= n; i ++) {
std::cin >> a[i];
}
for(int i = 0; i <= n; i ++) {
f[i][0] = f[i][1] = f[i][2] = f[i][3] = 1e18;
}
f[1][3] = 0;
for(int i = 2; i <= n; i ++) {
ll val1[4] = {0, s, a[i - 1] - s, a[i - 1]};
ll val2[4] = {0, s, a[i] - s, a[i]};
for(int j = 0; j <= 3; j ++) {
for(int k = 0; k <= 3; k ++) {
if(i != n) {
if(a[i] > s && (k == 0 || k == 3)) continue;
if(a[i] < s && (k == 1 || k == 2)) continue;
}
f[i][k] = std::min(f[i][k], f[i - 1][j] + val1[j] * (a[i] - val2[k]));
}
}
}
std::cout << f[n][0] << '\n';
}
return 0;
}
os:DP好差。。。
D. Game on Axis
![](https://img-blog.csdnimg.cn/img_convert/d4af33fe9d301f57ce938b8af12981c2.png)
给出一个长为n的数组a,从1点开始,如果当前位置在[1, n]之间,那就可以跳到i + a[i]位置,否则游戏结束。在开始之前,我们可以选择一个x和一个y,将a[x]修改为y,使得有限次的跳转后,游戏结束。求不同(x, y)组数,使得修改后的数组满足条件。
思路:思路来自严格鸽
关于n + 1 和2 * n + 1的解释:
n + 1:在主干路上的可以一步跳出去,共有n + 1种方法;
2 * n + 1:不在主干路上的,可以任意赋值,共有2 * n + 1种方法。
AC Code:
#include <bits/stdc++.h>
typedef long long ll;
#define INF 0x3f3f3f3f
#define int long long
const int N = 2e5 + 5;
int t, n;
int a[N], dis[N];
bool vis1[N], vis2[N];
int DFS1(int u) {
if(u < 1 || u > n) return 0;
if(vis1[u]) return dis[u];
vis1[u] = 1;
return dis[u] = DFS1(u + a[u]) + 1;
}
int DFS2(int u) {
if(u < 1 || u > n) return 0;
if(vis1[u] || vis2[u]) return dis[u];
vis2[u] = 1;
return dis[u] = DFS2(u + a[u]);
}
signed main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin >> t;
while(t --) {
std::cin >> n;
for(int i = 1; i <= n; i ++) {
std::cin >> a[i];
}
for(int i = 1; i <= n; i ++) {
vis1[i] = vis2[i] = 0, dis[i] = INF;
}
DFS1(1);
for(int i = 2; i <= n; i ++) {
DFS2(i);
}
std::vector<int> vec;
for(int i = 1; i <= n; i ++) {
if(dis[i] < INF) vec.push_back(dis[i]);
}
std::sort(vec.begin(), vec.end());
int ans = 0;
for(int i = 1; i <= n; i ++) {
if(vis1[i]) {
ans += n + 1;
int next = lower_bound(vec.begin(), vec.end(), dis[i]) - vec.begin();
ans += next;
}
else if(dis[1] < INF)
ans += 2 * n + 1;
}
std::cout << ans << '\n';
}
return 0;
}
E. The Harmonization of XOR
![](https://img-blog.csdnimg.cn/img_convert/037d827bfb57aff702ceec72e60566a5.png)
![](https://img-blog.csdnimg.cn/img_convert/2da18df549b576c3feddc59c86d15179.png)
给出一个permutat,长度为n,不重不漏的构造k组,每一组的异或和是x,给出构造方案,或者判断不存在方案。
思路:首先要满足所有数的异或和和k个x异或和相等,否则直接no;然后构造一个x,统计可以贡献x最高位数字的个数,不能少于k;若前两条都满足,则x为一组,再两两配对组成k - 2组,剩下的为一组。
AC Code:
#include <bits/stdc++.h>
typedef long long ll;
#define INF 0x3f3f3f3f
const int N = 2e5 + 5;
int t, n, k, x;
int main() {
std::ios::sync_with_stdio(false);
std::cin.tie(0);
std::cout.tie(0);
std::cin >> t;
while(t --) {
std::cin >> n >> k >> x;
int sum = (k % 2 ? x : 0);
for(int i = 1; i <= n; i ++) {
sum ^= i;
}
int tot = 0;
for(int i = 1; i <= n; i ++) {
if((x & i) > x / 2)
tot ++;
}
if(sum != 0 || tot < k) {
std::cout << "NO" << '\n';
continue;
}
std::cout << "YES" << '\n';
if(k == 1) {
std::cout << n << ' ';
for(int i = 1; i <= n; i ++) {
std::cout << i << ' ';
}
std::cout << '\n';
}
else {
int cnt = 0;
std::set<int> ss;
for(int i = 1; i <= n; i ++) {
ss.insert(i);
}
if(ss.count(x)) {
std::cout << 1 << ' ' << x << '\n';
cnt ++;
ss.erase(x);
}
for(int i = 1; i <= n; i ++) {
if(!ss.count(i) || !ss.count(i ^ x)) continue;
if(cnt == k - 1) break;
cnt ++;
std::cout << 2 << ' ' << i << ' ' << (i ^ x) << '\n';
ss.erase(i);
ss.erase(i ^ x);
}
std::cout << ss.size() << ' ';
for(auto i : ss)
std::cout << i << ' ';
std::cout << '\n';
}
}
return 0;
}