hdu 多校赛 第四场
slove 2/10
rank 391
补题 5/10
---------------------------------------------------
link
6614 AND Minimum Spanning Tree
题意: 给出n个点每个点的值是i ,规定点与点之间的边的值是i&j ,要求是这个图联通的最小的边的值的和,并且输出字典序最小的结果。
做法: 首先考虑除1以外的每一个点,以i为例,假如i为偶数那么和1连边的代价最低是0 假如i不为偶数,则考虑二进制,;例如i的二进制是1101那么取10 也就是2的代价最小,如果i的二进制是1111那么取10000代价最小,如果10000大于n则只能取1代价为1.
实现代码就是首先初始化每一个数的二进制下的第一个不为1的数位。然后1-n扫过去就行
#include<bits/stdc++.h>
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
const int MAX = 2e5 + 5;
const int INF = 0x3f3f3f3f;
int n, a[MAX], binary[MAX];
int Ans[MAX];
void solve() {
for (int i = 2; i <= 2e5; i++)
{
int temp = i, tot = 0;
binary[i] = 64;
while (temp != 0)
{
if (temp % 2 == 0)
{
binary[i] = tot;
break;
}
temp /= 2;
tot++;
}
}
int t;
scanf("%d", &t);
while (t--) {
scanf("%d", &n);
int ans = 0;
for (int i = 2; i <= n; i++)
{
if (binary[i] == 64 && n > i)
ans += 0, Ans[i] = i + 1;
else if (binary[i] == 64)
ans += 1, Ans[i] = 1;
else
ans += 0, Ans[i] = 1 << binary[i];
}
printf("%d\n", ans);
for (int i = 2; i <= n; i++)
printf(i == n ? "%d\n" : "%d ", Ans[i]);
}
}
int main(void)
{
solve();
return 0;
}
6616 Divide the Stones
两个数字n,k,表示有n块石头,第 i 块石头重量为 i,能否将这 n 块石头分为 k 份,并且使得 k 份的重量相等。
保证 k 是 n 的因子
1、n块石头的总和是,分为k份后每份的的重量是,每份的石头个数是
2、首先假设 n 是偶数,并且每份的石头的个数是偶数,那么每2k个石头,前k个石头顺序给,后k个石头顺序给,给完 n 个石头直接输出答案就可以了
3、如果每块石头的个数是奇数,那么每块石头的重量就是浮点数,显然不合法。
4、如果 n 是奇数,那么每份石头的个数和 k 也一定是奇数,那么考虑先把 3*k 个因子分成 3 等份,然后剩下的 n - 3*k 个就是偶数个了,按照方法2来分剩下的石头就可以找到满足答案的条件了。
5、问题在于如果把 3*k 个石头分为相等的3份,手玩几组案例,
先把前 k 个顺序给,然后k+1个到2*k个顺序下移k/2+1个,然后算一下剩下的数字是多少,加一下就可以啦。
n=15 k=5 的情况如下
1 8 15
2 9 13
3 10 11
4 6 14
5 7 12
#include <bits/stdc++.h>
#define ll long long
#define sc scanf
#define pr printf
using namespace std;
vector<int>v[100005];
ll sum[100005];
int main()
{
int T;
sc("%d", &T);
while (T--)
{
int n, k;
sc("%d%d", &n, &k);
for (int i = 1; i <= k; i++)
{
sum[i] = 0;
v[i].clear();
}
if (n == k)
{
if (n == 1)
{
printf("yes\n");
printf("1\n");
}
else
printf("no\n");
}
else if (n % 2 == 0 && (n / k) % 2 == 0)
{
int now = 0;
int f = 0;
while (now < n)
{
if (f)
{
for (int i = 1; i <= k; i++)
v[i].push_back(now + i);
}
else
{
for (int i = 1; i <= k; i++)
v[i].push_back(now + k + 1 -i);
}
now += k;
f ^= 1;
}
printf("yes\n");
for (int i = 1; i <= k; i++)
{
int sz = v[i].size();
for (int j = 0; j < sz; j++)
printf("%d%c", v[i][j], j == sz - 1 ? '\n' : ' ');
}
}
else if (n % 2 == 0 && (n / k) % 2 == 1)
{
printf("no\n");
}
else
{
for (int i = 1; i <= k; i++)
v[i].push_back(i);
for (int i = 1; i <= k / 2 + 1; i++)
v[i].push_back(k + k / 2 + i);
for (int i = k / 2 + 1 + 1; i <= k; i++)
v[i].push_back(k + i - k / 2 - 1);
for (int i = 1; i <= k; i++)
v[i].push_back((3 * k + 1) / 2 * 3 - v[i][0] - v[i][1]);
int now = 3 * k;
int f = 0;
while (now < n)
{
if (f)
{
for (int i = 1; i <= k; i++)
v[i].push_back(now + i);
}
else
{
for (int i = 1; i <= k; i++)
v[i].push_back(now + k + 1 - i);
}
now += k;
f ^= 1;
}
printf("yes\n");
for (int i = 1; i <= k; i++)
{
int sz = v[i].size();
for (int j = 0; j < sz; j++)
printf("%d%c", v[i][j], j == sz - 1 ? '\n' : ' ');
}
}
}
}
6620 Just an Old Puzzle
给一个4*4的拼图,问能否还原。
逆序数+0的位置。
#include <bits/stdc++.h>
#define ll long long
using namespace std;
bool num[18];
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
memset(num, false, sizeof(num));
int t, ans = 0;
for (int i = 1; i <= 4; i++)
{
for (int j = 1; j <= 4; j++)
{
scanf("%d", &t);
if (t == 0)
ans += i + j;
num[t] = true;
for (int k = t + 1; k <= 16; k++)
if (num[k] == true)
ans++;
}
}
if (ans & 1)
printf("Yes\n");
else
printf("No\n");
}
}
6621 K-th Closest Distance
区间中查询离某个数字第K近的数字
主席树+二分,强制在线,赛时看到K比较小,直接暴力,然后超时,忘了写之前提出的二分思路,T到爆炸。
#include <bits/stdc++.h>
#define ll long long
#define imid int mid=(left+right)/2;
using namespace std;
struct node
{
int l;
int r;
ll sum;
}tree[100005 * 55];
int root[100005], a[100005], t[100005], n, m, cnt;
int ql, qr, p, k, qq;
void init()
{
root[0] = 0;
tree[0].l = tree[0].r = tree[0].sum = 0;
cnt = 1;
}
void build(int num, int& rot, int left, int right)
{
tree[cnt++] = tree[rot];
rot = cnt - 1;
tree[rot].sum++;
if (left == right)
return;
imid;
if (num <= mid)
build(num, tree[rot].l, left, mid);
else
build(num, tree[rot].r, mid + 1, right);
}
int querycnt(int pre, int nex, int L, int R, int left, int right)
{
if (L <= left && right <= R)
return tree[nex].sum - tree[pre].sum;
imid;
int ans = 0;
if (L <= mid)
ans += querycnt(tree[pre].l, tree[nex].l, L, R, left, mid);
if (R > mid)
ans += querycnt(tree[pre].r, tree[nex].r, L, R, mid + 1, right);
return ans;
}
bool check(int r)
{
int L = lower_bound(t + 1, t + 1 + qq, p - r) - t;
int R = upper_bound(t + 1, t + 1 + qq, p + r) - t - 1;
int res = querycnt(root[ql - 1], root[qr], L, R, 1, n);
if (res >= k)
return true;
return false;
}
int main()
{
int T;
scanf("%d", &T);
while (T--)
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
{
scanf("%d", &a[i]);
t[i] = a[i];
}
sort(t + 1, t + 1 + n);
qq = unique(t + 1, t + 1 + n) - t - 1;
for (int i = 1; i <= n; i++)
a[i] = lower_bound(t + 1, t + 1 + qq, a[i]) - t;
init();
for (int i = 1; i <= n; i++)
{
root[i] = root[i - 1];
build(a[i], root[i], 1, n);
}
int X = 0;
while (m--)
{
scanf("%d%d%d%d", &ql, &qr, &p, &k);
ql ^= X, qr ^= X, p ^= X, k ^= X;
int l = 0, r = 1e6 + 5;
while (l + 1 < r)
{
int k = (l + r) / 2;
if (check(k))
r = k;
else
l = k;
}
if (!check(l))
l = r;
printf("%d\n", l);
X = l;
}
}
}
/*
5 4
1 2 3 4 5
1 3 2 3
1 5 2 4
1 4 4 5
2
3
1
*/
6623 Minimal Power of Prime
找出这个数字质因数分解后的最小指数。
分块暴力,先将4000内的素数筛出来,然后指数最大就是4,然后对他开四方,三方,二分,如果是整数开方的指数就是答案,否则答案是1.
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const int MAXN = 4000;
int prime[MAXN];
int cnt;
bool vis[MAXN];
void Eluer()
{
for (int i = 2; i < MAXN; i++)
{
if (vis[i] == false)
prime[cnt++] = i;
for (int j = 0; i * prime[j] < MAXN && j < cnt; j++)
{
vis[i * prime[j]] = true;
if (i % prime[j] == 0)
break;
}
}
}
ll fang(ll n, int t)
{
ll l = 1, r = n;
while (l <= r)
{
ll m = (l + r) / 2;
double tt = 1;
ll x = 1;
for (int i = 0; i < t; i++)
{
tt = tt * m;
if (tt > 2e18)
{
x = 2e18;
break;
}
x = x * m;
}
if (x < n)
l = m + 1;
else
r = m - 1;
}
return l;
}
ll power(ll a, int b)
{
ll res = 1;
while (b--)
res *= a;
return res;
}
int main()
{
Eluer();
int T;
scanf("%d", &T);
while (T--)
{
ll n;
scanf("%lld", &n);
int ans = 999;
for (int i = 0; i < cnt&&prime[i]<=n; i++)
{
if (n % prime[i] == 0)
{
int tot = 0;
while (n % prime[i] == 0)
{
tot++;
n /= prime[i];
}
ans = min(ans, tot);
}
}
if (n == 1 || ans == 1)
printf("%d\n", ans);
else if (power(fang(n, 4), 4) == n)
printf("%d\n", min(ans, 4));
else if (power(fang(n, 3), 3) == n)
printf("%d\n", min(ans, 3));
else if (power(fang(n, 2), 2) == n)
printf("%d\n", min(ans, 2));
else
printf("%d\n", 1);
}
}