2019 Multi-University Training Contest 4
A.AND Minimum Spanning Tree
贪心连边即可,对于一个数(x),如果其二进制位在低位存在(0),那么就连向最小的(0)的位置;否则就说明(x)为(11111)这种形式,如果最高位再加一位在题目范围内就连向它;否则连向(1)即可。
Code
#include<bits/stdc++.h>
typedef long long ll;
const int MAXN = 2e5 + 5, MAXM = 3e5 + 5, INF = 0x3f3f3f3f, MOD = 998244353;
const ll INFL = 0x3f3f3f3f3f3f3f3f;
using namespace std;
const int oo = (1e9) - (1e6);
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define mid l + ((r-l)>>1)
#define pb push_back
#define RR register
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define all(v) (v.begin(),v.end())
#define lc(x) c[x][0]
#define rc(x) c[x][1]
typedef long double db;
typedef unsigned int uint;
int t, n;
vector<int> ans;
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> t;
while (t--) {
ans.clear();
cin >> n;
int m = 1;
while (m * 2 <= n)m <<= 1;
int b = 2;
ll res = 0;
for (int i = 2; i <= m; i++) {
if (i > b)b <<= 1;
bool flag = false;
for (int j = 0; (1 << j) <= i; j++) {
if (!(i >> j & 1)) {
ans.push_back(1 << j);
flag = true;
break;
}
}
if (!flag)ans.push_back(b);
}
for (int i = m + 1; i <= n; i++) {
bool flag = false;
for (int j = 0; (1 << j) <= i; j++) {
if (!(i >> j & 1)) {
ans.push_back(1 << j);
flag = true;
break;
}
}
if (!flag)ans.push_back(1), res++;
}
cout << res << '
';
for (int i = 0; i < ans.size(); i++)cout << ans[i] << "
"[i == ans.size() - 1];
}
return 0;
}
D.Divide the Stones
手推(frac{n}{k}=1,2,3)的情况,令(t=frac{n}{k}),构造的时候将(t)不断缩小规模就行了。
注意一下特殊情况的判断。
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5 +5;
int T;
int n, k;
vector <int> v[N];
void solve2(int l, int r) {
for(int i = 1; i <= k; i++) {
v[i].push_back(l);
v[i].push_back(r);
l++; r--;
}
}
void solve3(int l, int r) {
int tot = (1ll * r * (r + 1) / 2) / k;
for(int i = 1; i <= k; i++) {
v[i].push_back(r);
r--;
}
int tmp = 1;
for(int i = 1; i <= k; i++) {
v[i].push_back(tmp);
tmp += 2;
if(tmp > k) tmp = 2;
}
for(int i = 1; i <= k; i++) {
int sz = v[i].size();
v[i].push_back(tot - v[i][sz - 1] - v[i][sz - 2]);
}
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> T;
while(T--) {
cin >> n >> k;
if((1ll * (n + 1) * n / 2) % k != 0) {
cout << "no" << '
';
continue;
}
if(n == k) {
if(n == 1) cout << "yes" << '
' << 1 << '
';
else cout << "no" << '
';
continue;
}
for(int i = 1; i <= k; i++) v[i].clear();
int t = n / k;
int tmp = t;
while(tmp > 3) {
solve2(n - 2 * k + 1, n);
tmp -= 2;
n -= 2 * k;
}
if(tmp == 3) solve3(1, n);
else solve2(1, n);
cout << "yes" << '
';
for(int i = 1; i <= k; i++) {
for(auto x : v[i]) cout << x << ' ';
cout << '
';
}
}
return 0;
}
G.Just an Old Puzzle
结论题,跟两种局面下逆序对的奇偶性和行差的奇偶性有关
Code
#include<bits/stdc++.h>
typedef long long ll;
const int MAXN = 2e5 + 5, MAXM = 3e5 + 5, INF = 0x3f3f3f3f, MOD = 998244353;
const ll INFL = 0x3f3f3f3f3f3f3f3f;
using namespace std;
const int oo = (1e9) - (1e6);
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define mid l + ((r-l)>>1)
#define pb push_back
#define RR register
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define all(v) (v.begin(),v.end())
#define lc(x) c[x][0]
#define rc(x) c[x][1]
typedef long double db;
typedef unsigned int uint;
int t, a;
vector<int> v;
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> t;
while (t--) {
v.clear();
int r = 0;
for (int i = 1; i <= 4; i++) {
for (int j = 1; j <= 4; j++) {
cin >> a;
if (a)v.push_back(a);
else r = i;
}
}
r = 4 - r;
int d = 0;
for (int i = 0; i < 15; i++) {
for (int j = i + 1; j < 15; j++) {
if (v[j] < v[i])d ^= 1;
}
}
r %= 2;
if (!(d^r))cout << "Yes
";
else cout << "No
";
}
return 0;
}
H.K-th Closest Distance
一开始被(k)的范围坑了,直接(T)飞= =
注意等价条件,如果一个(p)到(x)的距离为第(k)大,那么(|p-x|,|p+x|)这个区间范围有(k)个数。
然后二分就行了。
代码如下:
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 2e5 + 5;
int T;
int a[N], b[N];
int n, m;
int rt[N], sum[N * 20], ls[N * 20], rs[N * 20];
int tot;
void build(int &o, int l, int r) {
o = ++tot;
sum[o] = 0;
if(l == r) return ;
int mid = (l + r) >> 1;
build(ls[o], l, mid); build(rs[o], mid + 1, r);
}
void insert(int last, int &o, int l, int r, int v) {
o = ++tot;
ls[o] = ls[last]; rs[o] = rs[last];
sum[o] = sum[last] + 1;
if(l == r) return;
int mid = (l + r) >> 1;
if(v <= mid) insert(ls[last], ls[o], l, mid, v);
else insert(rs[last], rs[o], mid + 1, r, v);
}
int query(int last, int o, int l, int r, int L, int R) {
if(L <= l && r <= R) return sum[o] - sum[last];
int mid = (l + r) >> 1, ans = 0;
if(L <= mid) ans += query(ls[last], ls[o], l, mid, L, R);
if(R > mid) ans += query(rs[last], rs[o], mid + 1, r, L, R);
return ans;
}
int main() {
ios::sync_with_stdio(false); cin.tie(0);
cin >> T;
while(T--) {
cin >> n >> m;
for(int i = 1; i <= n; i++) cin >> a[i], b[i] = a[i];
sort(b + 1, b + n + 1);
int D = unique(b + 1, b + n + 1) - b - 1;
for(int i = 1; i <= n; i++) a[i] = lower_bound(b + 1, b + D + 1, a[i]) - b;
tot = 0; build(rt[0], 1, D);
for(int i = 1; i <= n; i++) insert(rt[i - 1], rt[i], 1, D, a[i]);
int last = 0;
while(m--) {
int l, r, p, k; cin >> l >> r >> p >> k;
l ^= last; r ^= last; p ^= last; k ^= last;
int L = 0, R = 1e6 + 1, mid;
while(L < R) {
mid = (L + R) >> 1;
int k1 = lower_bound(b + 1, b + n + 1, p - mid) - b;
int k2 = upper_bound(b + 1, b + n + 1, p + mid) - b - 1;
if(query(rt[l - 1], rt[r], 1, D, k1, k2) >= k) R = mid;
else L = mid + 1;
}
last = R; cout << last << '
';
}
}
return 0;
}
J.Minimal Power of Prime
暴力筛去(4000)以内的素数,那么最终将(n)分解质因子指数和不会超过(4)。
考虑各种情况的答案,答案为(4)时,就是(p^4)的形式;答案为(3)时,就是(p^3);答案为(2)时,就是(p^2q^2);答案为(1)时就是其它情况。
然后对于这三种直接开方判断就行,注意一下顺序就行了。
用(pow)的时候加个(round)会减小误差。
代码如下:
Code
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 4001;
bool vis[N];
int prime[N], tot;
void pre() {
for(int i = 2; i < N; i++) {
if(!vis[i]) {
prime[++tot] = i;
for(int j = i * i; j < N; j += i) vis[j] = 1;
}
}
}
int T;
ll n;
int main() {
ios::sync_with_stdio(false); cin.tie(0);
pre();
cin >> T;
while(T--) {
cin >> n;
int ans = 100;
for(int i = 1; i <= tot; i++) {
if(n % prime[i] == 0) {
int cnt = 0;
while(n % prime[i] == 0) cnt++, n /= prime[i];
if(cnt) ans = min(ans, cnt);
}
}
ll a = round(pow(n, 1 / 4.0));
ll b = round(pow(n, 1 / 3.0));
ll c = round(pow(n, 1 / 2.0));
if(a > 1 && a * a * a * a == n) ans = min(ans, 4);
else if(b > 1 && b * b * b == n) ans = min(ans, 3);
else if(c > 1 && c * c == n) ans = min(ans, 2);
else if(n > 1) ans = 1;
cout << ans << '
';
}
return 0;
}