版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39972971/article/details/82184245
【比赛链接】
【题解链接】
**【A】**Find Square
【思路要点】
- 答案即为所有黑色方格坐标的平均值。
- 时间复杂度 。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
write(x);
puts("");
}
int n, m, sx, sy, cnt;
int main() {
read(n), read(m);
for (int i = 1; i <= n; i++) {
static char s[MAXN];
scanf("\n%s", s + 1);
for (int j = 1; j <= m; j++)
if (s[j] == 'B') {
cnt++;
sx += i;
sy += j;
}
}
printf("%d %d\n", sx / cnt, sy / cnt);
return 0;
}
**【B】**Unnatural Conditions
【思路要点】
- 我们可以构造两个和为 的数,使得它们能够回答任何输入。
- 令 即可。
- 时间复杂度 。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
write(x);
puts("");
}
int main() {
string a, b;
for (int i = 1; i <= 1000; i++) {
a += '4';
b += '5';
}
a += '5', b += '5';
cout << a << endl;
cout << b << endl;
return 0;
}
**【C】**Rectangles
【思路要点】
- 用前/后缀和计算矩形的交,就可以在 的时间内得出除去任何一个矩形后其余矩形的交。
- 枚举去掉的矩形,若剩余矩形的交非空,输出其中任意一点。
- 时间复杂度 。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 200005;
const int INF = 1e9;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
write(x);
puts("");
}
struct point {int x, y; };
point min(point a, point b) {return (point) {min(a.x, b.x), min(a.y, b.y)}; }
point max(point a, point b) {return (point) {max(a.x, b.x), max(a.y, b.y)}; }
point l[MAXN], r[MAXN], prel[MAXN], prer[MAXN], sufl[MAXN], sufr[MAXN];
int n;
int main() {
read(n);
for (int i = 1; i <= n; i++) {
read(l[i].x), read(l[i].y);
read(r[i].x), read(r[i].y);
}
prel[0] = sufl[n + 1] = (point) {-INF, -INF};
prer[0] = sufr[n + 1] = (point) {INF, INF};
for (int i = 1; i <= n; i++) {
prel[i] = max(prel[i - 1], l[i]);
prer[i] = min(prer[i - 1], r[i]);
}
for (int i = n; i >= 1; i--) {
sufl[i] = max(sufl[i + 1], l[i]);
sufr[i] = min(sufr[i + 1], r[i]);
}
for (int i = 1; i <= n; i++) {
point tl = max(prel[i - 1], sufl[i + 1]);
point tr = min(prer[i - 1], sufr[i + 1]);
if (tl.x <= tr.x && tl.y <= tr.y) {
printf("%d %d\n", tl.x, tl.y);
return 0;
}
}
return 0;
}
**【D】**Order book
【思路要点】
- 考虑一个 操作带来的影响,被 的 (令其价格为 )的类型不能由此次操作确定,但当时存在的价格大于 的 必须为 ,当时存在的价格小于 的 必须为 。
- 在最后一个 操作前的 操作加进的 在上述过程考虑结束后若必须为 ,则方案数不变;若同时必须是 和 ,则不存在合法方案;否则,它既可以是 ,也可以是 ,方案数应当乘以 (注意此时这个 一定被 了)。
- 在最后一个 操作后的 操作需要单独考虑,若一个 被加入时已经小于某一个 ,或大于某一个 ,那么它的类型时确定的,否则,它的类型是不确定的。记不确定的 个数为 ,答案应当再乘以 。
- 用 来模拟上述过程,时间复杂度 。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 400005;
const int P = 1e9 + 7;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
write(x);
puts("");
}
bool type[MAXN]; int x[MAXN];
map <int, bool> black, white, exist;
priority_queue <int> hb, hw;
int main() {
int n; read(n);
int last = 0;
for (int i = 1; i <= n; i++) {
char opt[15];
scanf("\n%s%d", opt + 1, &x[i]);
type[i] = opt[2] == 'D';
if (!type[i]) last = i, exist[x[i]] = true;
}
for (int i = 1; i <= n; i++)
if (type[i]) {
hb.push(-x[i]);
hw.push(x[i]);
} else {
while (!hb.empty() && hb.top() >= -x[i]) {
if (hb.top() != -x[i]) black[-hb.top()] = true;
hb.pop();
}
while (!hw.empty() && hw.top() >= x[i]) {
if (hw.top() != x[i]) white[hw.top()] = true;
hw.pop();
}
}
int ans = 1, Max = 0, Min = 1e9;
for (int i = 1; i <= last; i++)
if (type[i]) {
int tmp = 0;
tmp += !black[x[i]];
if (black[x[i]] && !exist[x[i]]) chkmax(Max, x[i]);
tmp += !white[x[i]];
if (white[x[i]] && !exist[x[i]]) chkmin(Min, x[i]);
ans = ans * tmp % P;
}
int cnt = 1;
for (int i = last + 1; i <= n; i++)
if (x[i] >= Max && x[i] <= Min) cnt++;
writeln(1ll * ans * cnt % P);
return 0;
}
**【E】**Restore Array
【思路要点】
- 我们首先考虑所有数都相等的情况。
- 若所有数都等于 ,那么任意一组所有数都相同的解都可以作为答案。
- 若所有数都相等,且不为 ,那么问题无解。
- 接下来我们认为至少存在两个数不等。
- 注意到 。
- 令 ,取 使得 ,令 。
- 若 ,令 ,否则令 。
- 对于剩余所有 ,令 即可。
- 时间复杂度 。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 200005;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
write(x);
puts("");
}
int n, Max, a[MAXN];
long long ans[MAXN];
int main() {
read(n);
for (int i = 1; i <= n; i++)
read(a[i]), chkmax(Max, a[i]);
if (Max == 0) {
printf("YES\n");
for (int i = 1; i <= n; i++)
printf("%d ", 1);
printf("\n");
return 0;
}
a[0] = a[n];
for (int i = 1; i <= n; i++)
if (a[i] == Max && a[i - 1] != Max) {
long long now = a[i];
int pos = i - 1; ans[i] = now;
if (pos == 0) pos = n;
while (pos != i) {
if (a[pos] == 0 && now == a[i]) now += a[i];
else now += a[pos];
ans[pos] = now;
if (--pos == 0) pos = n;
}
printf("YES\n");
for (int i = 1; i <= n; i++)
write(ans[i]), putchar(' ');
printf("\n");
return 0;
}
printf("NO\n");
return 0;
}
**【F】**Make Symmetrical
【思路要点】
- 两个关于过原点的某条直线对称的点到原点距离相等。
- 而不定方程 的非负整数解的个数至多有 个。
- 对每个点按照到原点的距离分类,在插入或删除时暴力维护即可。
- 时间复杂度 。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 100005;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
write(x);
puts("");
}
struct point {int x, y; };
point operator + (point a, point b) {return (point) {a.x + b.x, a.y + b.y}; }
point operator - (point a, point b) {return (point) {a.x - b.x, a.y - b.y}; }
point operator * (point a, int b) {return (point) {a.x * b, a.y * b}; }
point operator / (point a, int b) {return (point) {a.x / b, a.y / b}; }
long long moo(point a) {return a.x * a.x + a.y * a.y; }
bool operator < (point a, point b) {
if (a.x == b.x) return a.y < b.y;
else return a.x < b.x;
}
int gcd(int x, int y) {
if (y == 0) return x;
else return gcd(y, x % y);
}
int n, tot, cnt;
map <point, int> ans;
map <long long, int> mp;
vector <point> a[MAXN];
int main() {
read(n);
for (int i = 1; i <= n; i++) {
int opt; point tmp;
read(opt), read(tmp.x), read(tmp.y);
if (opt == 1) {
cnt++;
long long tnp = moo(tmp);
if (mp[tnp] == 0) mp[tnp] = ++tot;
int pos = mp[tnp];
ans[tmp / gcd(tmp.x, tmp.y)]++;
for (unsigned j = 0; j < a[pos].size(); j++) {
point sum = tmp + a[pos][j];
sum = sum / gcd(sum.x, sum.y);
ans[sum] += 2;
}
a[pos].push_back(tmp);
}
if (opt == 2) {
cnt--;
long long tnp = moo(tmp);
if (mp[tnp] == 0) mp[tnp] = ++tot;
int pos = mp[tnp];
ans[tmp / gcd(tmp.x, tmp.y)]--;
for (unsigned j = 0; j < a[pos].size(); j++)
if (tmp.x == a[pos][j].x && tmp.y == a[pos][j].y) {
a[pos].erase(a[pos].begin() + j);
break;
}
for (unsigned j = 0; j < a[pos].size(); j++) {
point sum = tmp + a[pos][j];
sum = sum / gcd(sum.x, sum.y);
ans[sum] -= 2;
}
}
if (opt == 3) writeln(cnt - ans[tmp / gcd(tmp.x, tmp.y)]);
}
return 0;
}
**【G】**Guess the number
【思路要点】
记 表示剩余 次询问的机会,当前确定了 的情况下,能够确定的最大长度。
设计出状态之后,是容易转移的:
并且注意到当 , ,因此我们可以利用该性质对上述过程进行剪枝。
恰好为 ,说明题目给出的限制实际上是最紧的。
利用 的结果进行交互即可。
时间复杂度 ,实际运行复杂度很不满。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 10005;
const int MAXM = 10;
const long long INF = 1e18;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
write(x);
puts("");
}
long long dp[MAXM][MAXN], a[MAXN];
long long times(long long a, long long b) {
if ((long double) a * b >= INF) return INF;
else return a * b;
}
int main() {
for (int i = 1; i <= 5; i++)
for (int j = 1; j <= 10000; j++) {
long long ans = -1, pos = j;
for (int k = 0; k <= j; k++) {
ans += dp[i - 1][pos] + 1;
chkmin(ans, INF);
pos += dp[i - 1][pos] + 1;
if (pos >= 10000) {
ans += times(dp[i - 1][10000] + 1, j - k);
chkmin(ans, INF);
break;
}
}
dp[i][j] = ans;
}
int cnt = 5; long long pos = 1;
while (true) {
int tmp = min(pos, 10000ll), tnp = tmp;
cout << tmp; a[0] = pos - 1;
for (int i = 1; i <= tmp; i++) {
pos += dp[cnt - 1][tnp];
tnp = min(tnp + dp[cnt - 1][tnp] + 1, 10000ll);
a[i] = pos; pos++;
cout << ' ' << a[i];
}
cout << endl;
read(tnp);
if (tnp == -1) return 0;
cnt--; pos = a[tnp] + 1;
}
return 0;
}
**【H】**Make Square
【思路要点】
- 首先我们可以将所有数的完全平方因子除去,只剩下每个质因数至多一种。
- 由此我们也可以看出,两种操作实际上是本质相同的,考虑只使用除法操作。
- 将两个数 的乘积修改为完全平方数的过程可以看做对 各进行若干次除法操作,使得它们等于同一个数 。
- 考虑离线询问,从左到右枚举询问的右端点 ,并维护数组 ,表示在前 个数中,进行 次除法操作可以得到 的最靠右的数的位置;再维护数组 表示使得答案为 的最靠右的左端点,显然有了 数组后是容易回答询问的。
- 对于每一个右端点 ,考虑 数组的变化,枚举 的因数 ,再枚举与 配为完全平方数的 得到 的操作次数,即可借助 数组更新 数组,对于 数组的更新类似。
- 时间复杂度 ,其中 。
【代码】
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 2e5 + 5;
const int MAXQ = 2e6 + 5;
const int MAXV = 6e6 + 5;
const int Maxans = 12;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); }
template <typename T> void read(T &x) {
x = 0; int f = 1;
char c = getchar();
for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
x *= f;
}
template <typename T> void write(T x) {
if (x < 0) x = -x, putchar('-');
if (x > 9) write(x / 10);
putchar(x % 10 + '0');
}
template <typename T> void writeln(T x) {
write(x);
puts("");
}
int n, q, a[MAXN], ans[MAXQ];
int r[Maxans + 5], Max[MAXV][Maxans + 5];
int tot, prime[MAXV], f[MAXV], cnt[MAXV];
vector <int> pos[MAXN], home[MAXN];
void init() {
for (int i = 2; i < MAXV; i++) {
if (f[i] == 0) prime[++tot] = f[i] = i, cnt[i] = 1;
for (unsigned j = 1; j <= tot && prime[j] <= f[i]; j++) {
int tmp = prime[j] * i;
if (tmp >= MAXV) break;
f[tmp] = prime[j];
cnt[tmp] = cnt[i] + 1;
}
}
}
int process(int x) {
int ans = 1;
for (int i = 1; prime[i] * prime[i] <= x; i++)
if (x % prime[i] == 0) {
int cnt = 0;
while (x % prime[i] == 0) x /= prime[i], cnt++;
if (cnt & 1) ans *= prime[i];
}
return ans * x;
}
int main() {
read(n), read(q);
init();
for (int i = 1; i <= n; i++) {
read(a[i]);
a[i] = process(a[i]);
}
for (int i = 1; i <= q; i++) {
int x, y; read(x), read(y);
pos[y].push_back(x);
home[y].push_back(i);
}
for (int i = 1; i <= n; i++) {
for (int j = 1; j * j <= a[i]; j++) {
if (a[i] % j == 0) {
int now = cnt[a[i] / j];
for (int k = 0; k + now <= Maxans; k++)
chkmax(r[k + now], Max[j][k]);
now = cnt[j];
for (int k = 0; k + now <= Maxans; k++)
chkmax(r[k + now], Max[a[i] / j][k]);
}
}
for (int j = 1; j * j <= a[i]; j++) {
if (a[i] % j == 0) {
chkmax(Max[j][cnt[a[i] / j]], i);
chkmax(Max[a[i] / j][cnt[j]], i);
}
}
for (unsigned j = 0; j < pos[i].size(); j++) {
int tans = Maxans;
for (int k = 0; k <= Maxans; k++)
if (r[k] >= pos[i][j]) chkmin(tans, k);
ans[home[i][j]] = tans;
}
}
for (int i = 1; i <= q; i++)
writeln(ans[i]);
return 0;
}