CodeTON Round 9 赛后复盘
C2. Shohag Loves XOR (Hard Version)
在赛时因为一处判断漏了相等的情况多调了 20min,蠢死我得了......
思路
我们可以选取从
因为我们知道当
再考虑能被
但是这还有一个问题,循环的次数太多了,这时我们不难发现
最后的代码逻辑就是:
- 先处理区间贡献
- 然后统计出
循环贡献 - 计算原数列中
循环贡献,此时剩余数列中不满一个 循环 - 计算原数列中每个剩余
区间的贡献,此时剩余不满 项 - 剩下的单独处理统计
AC 代码
c++
#include <algorithm>
#include <cmath>
#include <ctime>
#include <iostream>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <string>
#include <vector>
#define OOO cout << ">>>>"; // 调试标识
using namespace std;
mt19937_64 rnd(time(0));
typedef long long ll;
typedef uint64_t ull;
const ll INF = 1e18, Mod = 1e9 + 7;
ll tt;
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> tt;
while (tt--) {
ll x, m, ans = 0, ans1 = 0, ans2 = 0;
cin >> x >> m;
ll k = log2(x) + 1;
ll p = 1ll << k;
vector<ll> cnt(p + 1);
for (ll i = 1; i <= min(m, p); i++) {
if ((x ^ i) % i == 0 && (x ^ i) % x != 0)
ans1++;
cnt[(x ^ i) % x]++;
}
for (ll i = 1; i * p <= m && i <= x; i++)
ans2 += cnt[(x - ((i - 1) * p) % x) % x];
if (m >= x * p)
ans += (m / (x * p)) * ans2;
for (ll i = x * (m / (x * p)) + 1; i * p <= m; i++)
ans += cnt[(x - ((i - 1) * p) % x) % x];
for (ll i = p * (m / p) + 1; i <= m; i++)
if ((i ^ x) % x == 0)
ans++;
cout << ans + ans1 << endl;
}
cout.flush();
return 0;
}
D. Shohag Loves GCD
游记
赛后复盘发现自己虽然对于条件的转化正确了,但是在求解的时候没有保证最优,然而实际上的思路还是很暴力的,感觉就是自己做题少了,懒死我得了......
思路
在赛时的时候,想到了条件的等价:
- 对于
,有
那由于我们要求的是字典序最大,所以对于
- 对于
,有
那做法其实就很明确了,对于每一个位置,我们处理出它不能取的值,然后为其赋值,如果对于某一位找不到合法的值,则说明数列不存在
AC 代码
c++
#include <algorithm>
#include <cmath>
#include <ctime>
#include <iostream>
#include <map>
#include <queue>
#include <random>
#include <set>
#include <string>
#include <vector>
#define OOO cout << ">>>>"; // 调试标识
using namespace std;
mt19937_64 rnd(time(0));
typedef long long ll;
typedef uint64_t ull;
const ll INF = 1e18, Mod = 1e9 + 7;
ll tt;
int main() {
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
cin >> tt;
while (tt--) {
ll n, m;
cin >> n >> m;
vector<ll> v(m + 1), ans(n + 10);
set<ll, greater<ll>> s;
for (ll i = m; i >= 1; i--)
cin >> v[i], s.insert(v[i]);
ans[1] = *s.begin();
s.erase(s.begin());
if (n > 1 && s.empty()) {
cout << -1 << endl;
continue;
}
set<ll> k[n + 1];
for (ll i = 1; i <= n; i++) {
for (ll j = 1; j <= m && (!ans[i]); j++)
if (k[i].find(v[j]) == k[i].end())
ans[i] = v[j];
for (ll j = 2; i * j <= n; j++)
k[i * j].insert(ans[i]);
if (!ans[i])
break;
}
if (ans[n])
for (ll i = 1; i <= n; i++)
cout << ans[i] << ' ';
else
cout << -1;
cout << endl;
}
cout.flush();
return 0;
}
总结
- 要多做题,熟悉条件的转化和正确性的证明,漏掉其中任何一个都会让题目变得难做,或者让代码挂掉