虽然13分钟切完08给了极大自信,但是07又给了我当头一棒…
1001 AND Minimum Spanning Tree
解法:对于每个数,我们找它二进制下最右边第一个0即可,签到
#include
using namespace std;
const int maxn = 1e6 + 10;
int ans[maxn];
int main() {
int T;
cin>>T;
while (T--) {
int n;
cin>>n;
for (int i = 1; i <= n; i++)
p[i] = i;
int res = 0;
for (int i = 1; i <= n; i++) {
int flag = -1;
for (int j = 0; (1 << j) <= n; j++)
if (!(i >> j & 1)) {
flag = (1 << j);
break;
}
if (flag == -1)
ans[i] = 1, res += 1;
else
ans[i] = flag;
}
printf("%d\n", res);
for (int i = 2; i <= n; i++)
printf("%d%c", ans[i], (i == n) ? ' \n' : ' ');
}
}
1003 Divide the Stones
解法:假设n/k为偶数,举个例子:1 2 3 4 5 6,k = 3,那么很显然 1 和 6 放一组,2 和 5 一组 ,3 和 4 一组,如果 n / k 为奇数,那么怎么放呢?其实仔细分析也不能,举个例子:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15,k = 5,我们从15枚举到11,15 可以和1,8放一起,13可以和2,9放一起,11可以和3,10放一起,14 可以和6,4一组,12可以和7,5一组,相信你也能发现规律了吧
#include
#define ll long long
using namespace std;
const int maxn = 1e5 + 10;
vector<int> G[maxn];
int main() {
int Cas;
scanf("%d", &Cas);
while (Cas--) {
int n, k;
scanf("%d%d", &n, &k);
for (int i = 1; i <= k; i++)
G[i].clear();
if (k == 1) {
puts("yes");
for (int i = 1; i <= n; i++)
printf("%d%c", i, (i == n) ? '\n' : ' ');
continue;
}
int m = n / k;
if ((n / k) % 2 == 0) {
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= k; j++) {
int v = (i - 1) * k + j;
int cur = j;
if (i % 2 == 0)
cur = k + 1 - j;
G[cur].push_back(v);
}
}
puts("yes");
for (int i = 1; i <= k; i++)
for (int j = 0; j < G[i].size(); j++)
printf("%d%c", G[i][j], (j == G[i].size() - 1) ? '\n' : ' ');
continue;
}
int ok = 1;
for (int i = 4; i <= m; i++) {
for (int j = 1; j <= k; j++) {
int v = (i - 1) * k + j;
int cur = j;
if (i % 2 == 0)
cur = k + 1 - j;
G[cur].push_back(v);
}
}
ll T = 1ll * (1 + 3 * k) * (3 * k) / 2;
if (T % k)
ok = 0;
if (ok) {
T /= k;
for (int i = 3 * k; i > 2 * k; i--) {
int cur = i % k;
if (!cur)
cur = k;
cur = k - cur + 1;
G[cur].push_back(i);
ll tmp = T - i;
if (cur % 2) {
int tmp2 = cur / 2;
G[cur].push_back(tmp2 + 1);
G[cur].push_back(tmp - tmp2 - 1);
}
else {
int tmp2 = cur / 2 + k;
G[cur].push_back(tmp2);
G[cur].push_back(tmp - tmp2);
}
}
}
if (!ok)
puts("no");
else {
puts("yes");
for (int i = 1; i <= k; i++)
for (int j = 0; j < G[i].size(); j++)
printf("%d%c", G[i][j], (j == G[i].size() - 1) ? '\n' : ' ');
}
}
}
1006 Horse
待补
1007 Just an Old Puzzle
这个题的难度不应该这么多人ac啊…
1008 K-th Closest Distance
解法:首先先建立可持久化线段树,二分答案ans,然后从线段树中查询[p - ans, p + ans]的区间和是否大于等于k即可。
#include
using namespace std;
const int maxn = 1e5 + 10, N = 1e6;
int rt[maxn], ls[maxn * 22], rs[maxn * 22], sum[maxn * 22], cnt;
#define m (l + r) / 2
void up(int &o, int pre, int l, int r, int k) {
o = ++cnt;
sum[o] = sum[pre] + 1;
ls[o] = ls[pre];
rs[o] = rs[pre];
if (l == r)
return;
if (k <= m)
up(ls[o], ls[pre], l, m, k);
else
up(rs[o], rs[pre], m + 1, r, k);
}
int qu(int o, int pre, int l, int r, int ql, int qr) {
if (l >= ql && r <= qr)
return sum[o] - sum[pre];
int res = 0;
if (ql <= m)
res += qu(ls[o], ls[pre], l, m, ql, qr);
if (qr > m)
res += qu(rs[o], rs[pre], m + 1, r, ql, qr);
return res;
}
int gao(int x, int len, int l, int r) {
int L = max(x - len, 1);
int R = min(x + len, N);
return qu(rt[r], rt[l - 1], 1, N, L, R);
}
int main() {
int T;
scanf("%d", &T);
while (T--) {
int n, q, x, l, r, p, k, ans = 0;
cnt = 0;
scanf("%d%d", &n, &q);
for (int i = 1; i <= n; i++) {
scanf("%d", &x);
up(rt[i], rt[i - 1], 1, N, x);
}
while (q--) {
scanf("%d%d%d%d", &l, &r, &p, &k);
l ^= ans, r ^= ans, p ^= ans, k ^= ans;
int L = 0, R = 1e6;
while (L < R) {
int mid = (L + R) / 2;
if (gao(p, mid, l, r) < k)
L = mid + 1;
else
R = mid;
}
printf("%d\n", ans = L);
}
}
}
1010 Minimal Power of Prime
解法:对于每个数n,我们枚举10000以内的素数,然后把 n 去分解质因数,如果 n 分解完不为1,那么有4种情况,n是一个质数的4次方,n是一个质数的3次方,n是一个质数的2次方,n是一个或多个不同质数相乘得到,分别判断一下即可
#include
#define ll long long
using namespace std;
const int maxn = 1e4 + 100;
int vis[maxn], pri[maxn], cnt;
void init(int n) {
for (int i = 2; i <= n; i++) {
if (!vis[i])
pri[++cnt] = i;
for (int j = 1; j <= cnt && pri[j] * i <= n; j++) {
vis[i * pri[j]] = 1;
if (i % pri[j] == 0)
break;
}
}
}
ll gao(ll x, int y) {
ll res = 1;
while (y) {
res *= x;
y--;
}
return res;
}
int main() {
int T;
scanf("%d", &T);
init(maxn - 1);
while (T--) {
ll n;
scanf("%lld", &n);
int ans = 199;
for (int i = 1; i <= cnt && pri[i] <= n; i++)
if (n % pri[i] == 0) {
int res = 0;
while (n % pri[i] == 0)
res++, n /= pri[i];
ans = min(ans, res);
}
if (n == 1) {
printf("%d\n", ans);
continue;
}
int x = pow(n, 1.0 / 4);
if (gao(x, 4) == n || gao(x + 1, 4) == n || gao(x - 1, 4) == n)
ans = min(ans, 4);
else {
x = pow(n, 1.0 / 3);
if (gao(x, 3) == n || gao(x + 1, 3) == n || gao(x - 1, 3) == n)
ans = min(ans, 3);
else {
int x = pow(n, 0.5);
if (gao(x, 2) == n || gao(x + 1, 2) == n || gao(x - 1, 2) == n)
ans = min(ans, 2);
else
ans = 1;
}
}
printf("%d\n", ans);
}
}