H
考场上写了个假做法直接过了,补一补。qaq
由于每一个\(|a_i - a_j| \leqslant 5 \times 10^5\),所以只要知道所有的\(|a_i - a_j|\)就可以\(O(nlogn)\)求解,然而这样的\(|a_i - a_j|\)有\(O(n^2)\)个。
为卷积的基本模型,举个例子\((x + x^3 + x^5)(x^{-1} + x^{-3} + x^{-5})\)拆开之后就可以得到两两的差值,为了处理负数,两边可乘上一个\(x^5\)。
using namespace std;
typedef long long ll;
typedef double db;
typedef pair <int, int> pin;
const int N = 5e5 + 5;
const int Maxn = 5e5 + 1;
const ll P = 998244353LL;
int n, a[N];
bool ex[N], flag[N];
template <typename T>
inline void read(T &X) {
char ch = 0; T op = 1;
for (X = 0; ch > '9' || ch < '0'; ch = getchar())
if (ch == '-') op = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar())
X = (X * 10) + ch - '0';
X *= op;
}
typedef vector <ll> poly;
namespace Poly {
const int L = 1 << 20;
const ll P = 998244353LL;
int lim, pos[L];
inline ll fpow(ll x, ll y) {
ll res = 1;
for (; y > 0; y >>= 1) {
if (y & 1) res = res * x % P;
x = x * x % P;
}
return res;
}
const ll inv2 = fpow(2, P - 2);
template <typename T>
inline void inc(T &x, T y) {
x += y;
if (x >= P) x -= P;
}
template <typename T>
inline void sub(T &x, T y) {
x -= y;
if (x < 0) x += P;
}
inline void prework(int len) {
int l = 0;
for (lim = 1; lim < len; lim <<= 1, ++l);
for (int i = 0; i < lim; i++)
pos[i] = (pos[i >> 1] >> 1) | ((i & 1) << (l - 1));
}
inline void ntt(poly &c, int opt) {
c.resize(lim, 0);
for (int i = 0; i < lim; i++)
if (i < pos[i]) swap(c[i], c[pos[i]]);
for (int i = 1; i < lim; i <<= 1) {
ll wn = fpow(3, (P - 1) / (i << 1));
if (opt == -1) wn = fpow(wn, P - 2);
for (int len = i << 1, j = 0; j < lim; j += len) {
ll w = 1;
for (int k = 0; k < i; k++, w = w * wn % P) {
ll x = c[j + k], y = w * c[j + k + i] % P;
c[j + k] = (x + y) % P, c[j + k + i] = (x - y + P) % P;
}
}
}
if (opt == -1) {
ll inv = fpow(lim, P - 2);
for (int i = 0; i < lim; i++) c[i] = c[i] * inv % P;
}
}
inline poly operator * (const poly &x, const poly &y) {
poly res, u = x, v = y;
prework(u.size() + v.size() - 1);
ntt(u, 1), ntt(v, 1);
for (int i = 0; i < lim; i++) res.push_back(v[i] * u[i] % P);
ntt(res, -1);
res.resize(u.size() + v.size() - 1);
return res;
}
} using namespace Poly;
int main() {
freopen("sample.in", "r", stdin);
clock_t st_clock = clock();
read(n);
poly p1;
p1.resize(Maxn);
for (int i = 1; i <= n; i++) {
read(a[i]);
p1[a[i]] = 1;
}
poly p2 = p1;
reverse(p2.begin(), p2.end());
poly res = p1 * p2;
for (int i = Maxn - 1; i <= 2 * Maxn - 1; i++)
if (res[i] > 0)
ex[i - Maxn + 1] = 1;
for (int i = 1; i < Maxn; i++)
for (int j = i; j < Maxn; j += i)
if (ex[j]) {
flag[i] = 1;
break;
}
for (int i = n; ; i++)
if (!flag[i]) {
printf("%d\n", i);
break;
}
clock_t ed_clock = clock();
printf("time = %f ms\n", (double)(ed_clock - st_clock) / CLOCKS_PER_SEC * 1000);
return 0;
}
开了O2之后,这个vector写的多项式还是挺快的。
E
首先注意到每一个格子的状态和前面的格子都无关,只与进入的方向有关,所以这就是一个广搜问题,找到最快到达终点的方案就可以了。
需要注意的是一个格子可能不止到一次,特别是起点或是终点要特判一下,旋转之后要把当前状态保存下来,下一次旋转的时候要用。
难度在于把代码写对。
using namespace std;
typedef long long ll;
typedef double db;
typedef pair <int, int> pin;
typedef pair <pin, int> tin;
typedef vector <int> vec;
const int N = 1005;
const ll P = 998244353LL;
int n, m, cnt, a[N][N];
tin pre[N][N][4];
bool vis[N][N][4];
vector <vec> ansList;
enum DIR {
UP = 0,
RIGHT = 1,
DOWN = 2,
LEFT = 3
};
template <typename T>
inline void read(T &X) {
char ch = 0; T op = 1;
for (X = 0; ch > '9' || ch < '0'; ch = getchar())
if (ch == '-') op = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar())
X = (X * 10) + ch - '0';
X *= op;
}
inline bool valid(int x, int y) {
return x >= 1 && x <= n && y >= 1 && y <= m;
}
queue <tin> q;
inline void tryPush(int curx, int cury, int curd, int tod) {
int tox, toy;
if (tod == UP) {
tox = curx + 1, toy = cury;
} else if (tod == DOWN) {
tox = curx - 1, toy = cury;
} else if (tod == LEFT) {
tox = curx, toy = cury + 1;
} else {
/* RIGHT */
tox = curx, toy = cury - 1;
}
if (!valid(tox, toy)) return;
if (vis[tox][toy][tod]) return;
vis[tox][toy][tod] = 1;
tin to = tin(pin(tox, toy), tod);
pre[tox][toy][tod] = tin(pin(curx, cury), curd);
q.push(to);
}
inline bool bfs() {
for (; !q.empty(); q.pop());
q.push(tin(pin(1, 1), UP));
vis[1][1][UP] = 1;
for (; !q.empty(); ) {
tin cur = q.front();
q.pop();
int curx = cur.first.first, cury = cur.first.second, curd = cur.second;
if (curx == n && cury == m) {
if (a[curx][cury] <= 3 && curd == LEFT) return true;
if (a[curx][cury] > 3 && curd == UP) return true;
}
if (a[curx][cury] <= 3) {
if (curd == UP || curd == DOWN) {
tryPush(curx, cury, curd, LEFT);
tryPush(curx, cury, curd, RIGHT);
} else {
tryPush(curx, cury, curd, UP);
tryPush(curx, cury, curd, DOWN);
}
} else {
if (curd == UP) {
tryPush(curx, cury, curd, UP);
} else if (curd == DOWN) {
tryPush(curx, cury, curd, DOWN);
} else if (curd == LEFT) {
tryPush(curx, cury, curd, LEFT);
} else {
/* RIGHT */
tryPush(curx, cury, curd, RIGHT);
}
}
}
return false;
}
inline int get0_3s(int d1, int d2) {
if (d1 == UP || d1 == DOWN) {
if (d1 == UP) {
if (d2 == LEFT) return 1;
else return 0;
} else {
/* d1 == DOWN */
if (d2 == LEFT) return 2;
else return 3;
}
} else {
if (d1 == LEFT) {
if (d2 == UP) return 3;
else return 0;
} else {
/* d1 == RIGHT */
if (d2 == UP) return 2;
else return 1;
}
}
}
inline int get4_5s(int d1, int d2) {
if (d1 == UP || d1 == DOWN) return 5;
else return 4;
}
void printPath(int x, int y, int d) {
if (x == 1 && y == 1 && d == UP) return;
tin pres = pre[x][y][d];
int prex = pres.first.first, prey = pres.first.second, pred = pres.second;
printPath(prex, prey, pred);
if (prex == 1 && prey == 1 && pred == UP) {
if (a[prex][prey] <= 3 && a[prex][prey] != 1) {
// printf("1 %d %d %d\n", 90 * ((1 - a[prex][prey] + 4) % 4), prex, prey);
vec tmp;
tmp.push_back(1), tmp.push_back(90 * ((1 - a[prex][prey] + 4) % 4)), tmp.push_back(prex), tmp.push_back(prey);
ansList.push_back(tmp);
a[prex][prey] = 1;
}
if (a[prex][prey] > 3 && a[prex][prey] != 5) {
// printf("1 %d %d %d\n", 90, prex, prey);
vec tmp;
tmp.push_back(1), tmp.push_back(90), tmp.push_back(prex), tmp.push_back(prey);
ansList.push_back(tmp);
a[prex][prey] = 5;
}
// printf("0 %d %d\n", prex, prey);
vec move;
move.push_back(0), move.push_back(prex), move.push_back(prey);
ansList.push_back(move);
} else {
if (a[prex][prey] <= 3) {
int tos = get0_3s(pred, d);
if (a[prex][prey] != tos) {
// printf("1 %d %d %d\n", 90 * ((tos - a[prex][prey] + 4) % 4), prex, prey);
vec tmp;
tmp.push_back(1), tmp.push_back(90 * ((tos - a[prex][prey] + 4) % 4)), tmp.push_back(prex), tmp.push_back(prey);
ansList.push_back(tmp);
a[prex][prey] = tos;
}
} else {
int tos = get4_5s(pred, d);
if (a[prex][prey] != tos) {
// printf("1 %d %d %d\n", 90, prex, prey);
vec tmp;
tmp.push_back(1), tmp.push_back(90), tmp.push_back(prex), tmp.push_back(prey);
ansList.push_back(tmp);
a[prex][prey] = tos;
}
}
// printf("0 %d %d\n", prex, prey);
vec move;
move.push_back(0), move.push_back(prex), move.push_back(prey);
ansList.push_back(move);
}
if (x == n && y == m && ((a[x][y] <= 3 && d == LEFT) || (a[x][y] > 3 && d == UP))) {
if (a[x][y] <= 3) {
int tos = 3;
if (tos != a[x][y]) {
// printf("1 %d %d %d\n", 90 * ((3 - a[x][y]) % 4), x, y);
vec tmp;
tmp.push_back(1), tmp.push_back(90 * ((3 - a[x][y]) % 4)), tmp.push_back(x), tmp.push_back(y);
ansList.push_back(tmp);
a[x][y] = tos;
}
} else {
int tos = 5;
if (tos != a[x][y]) {
// printf("1 %d %d %d\n", 90, x, y);
vec tmp;
tmp.push_back(1), tmp.push_back(90), tmp.push_back(x), tmp.push_back(y);
ansList.push_back(tmp);
a[x][y] = tos;
}
}
// printf("0 %d %d\n", x, y);
vec move;
move.push_back(0), move.push_back(x), move.push_back(y);
ansList.push_back(move);
}
}
void calPath(int x, int y, int d) {
if (x == 1 && y == 1 && d == UP) return;
tin pres = pre[x][y][d];
int prex = pres.first.first, prey = pres.first.second, pred = pres.second;
calPath(prex, prey, pred);
if (prex == 1 && prey == 1 && pred == UP) {
if (a[prex][prey] <= 3 && a[prex][prey] != 1) ++cnt;
if (a[prex][prey] > 3 && a[prex][prey] != 5) ++cnt;
++cnt;
} else {
if (a[prex][prey] <= 3) {
int tos = get0_3s(pred, d);
if (a[prex][prey] != tos) ++cnt;
} else {
int tos = get4_5s(pred, d);
if (a[prex][prey] != tos) ++cnt;
}
++cnt;
}
if (x == n && y == m) {
if (a[x][y] <= 3) {
int tos = 3;
if (tos != a[x][y]) ++cnt;
} else {
int tos = 5;
if (tos != a[x][y]) ++cnt;
}
++cnt;
}
}
int main() {
freopen("sample.in", "r", stdin);
clock_t st_clock = clock();
int T;
read(T);
for (; T--; ) {
read(n), read(m);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
read(a[i][j]);
for (int k = 0; k < 4; k++) {
vis[i][j][k] = 0;
pre[i][j][k].first.first = pre[i][j][k].first.second = pre[i][j][k].second = 0;
}
}
if (!bfs()) puts("NO");
else {
puts("YES");
// cnt = 0;
// if (a[n][m] <= 3) calPath(n, m, LEFT);
// else calPath(n, m, UP);
// printf("%d\n", cnt);
// if (cnt > 20 * n * m) assert(0);
ansList.clear();
if (a[n][m] <= 3) printPath(n, m, LEFT);
else printPath(n, m, UP);
printf("%d\n", ansList.size());
for (auto ans : ansList) {
for (int i = 0; i < ans.size(); i++) {
printf("%d%c", ans[i], " \n"[i == ans.size() - 1]);
}
}
}
}
clock_t ed_clock = clock();
printf("time = %f ms\n", (double)(ed_clock - st_clock) / CLOCKS_PER_SEC * 1000);
return 0;
}
K
K题是个乱搞题,唯一不能无脑上的是sort,用一下柯西就会发现sort完之后刚好到了等号的另一边。
有一种直接局部调整的方法在实际应用中非常好,出题人给的做法是小数据跑km,大数据乱搞,可以把误差匀下去。
代码写的是那种调整法,调一次过不了,要多调几次。
using namespace std;
typedef long long ll;
typedef double db;
typedef pair <int, int> pin;
const int N = 1005;
const int Maxn = 1000;
const ll P = 998244353LL;
int T, n, a[N];
db sqr[N];
template <typename T>
inline void read(T &X) {
char ch = 0; T op = 1;
for (X = 0; ch > '9' || ch < '0'; ch = getchar())
if (ch == '-') op = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar())
X = (X * 10) + ch - '0';
X *= op;
}
inline db solve(int x, int y) {
return sqr[abs(x - y)];
}
int main() {
freopen("sample.in", "r", stdin);
clock_t st_clock = clock();
for (int i = 0; i <= Maxn; i++) sqr[i] = sqrt(i);
read(T);
for (; T--; ) {
read(n);
for (int i = 0; i < n; i++) read(a[i]);
for (int s = 1; s < n; s <<= 1)
for (int i = 0; i < n; i++)
for (int j = i + 1; j < n; j++) {
if (solve(i, a[j]) + solve(j, a[i]) < solve(i, a[i]) + solve(j, a[j]))
swap(a[i], a[j]);
}
for (int i = 0; i < n; i++)
printf("%d%c", a[i], " \n"[i == n - 1]);
}
clock_t ed_clock = clock();
printf("time = %f ms\n", (double)(ed_clock - st_clock) / CLOCKS_PER_SEC * 1000);
return 0;
}
J
不得不说做不出J题的原因和平时缺乏训练是分不开的,缓慢重练中zzzzz
采用出题人给的第二种做法,考察每一个限制条件,以\((1, 3)\)这个区间为例子,Yes的条件是
\[u_1 \leq v_1 \]
\[max(u_2, u_1 + d_1) \leq v_2 \]
\[max(max(u_2, u_1 + d_1) + d_2, u_3) \leq v_3 \]
设\(u_i' = u_i + d_i + d_{i + 1} + \cdots + d_{n - 1}, v_i' = v_i + d_i + d_{i + 1} + \cdots + d_{n - 1}\),Yes的条件就变成了
\[u_1' \leq v_1' \]
\[max(u_1', u_2') \leq v_2' \]
\[max(u_1', u_2', u_3') \leq v_3' \]
线段树维护\(u'\)的最大值,\(v'\)的最小值,以及当前区间是否可行,区间可行的条件两边都可行并且\(mxu(lc) \leq mnr(rc)\);于是变成单点加、区间修改、查询。
using namespace std;
typedef long long ll;
typedef double db;
typedef pair <int, int> pin;
const int N = 1e6 + 5;
const ll P = 998244353LL;
int T, n, qn;
ll d[N], sum[N], ln[N], rn[N];
template <typename T>
inline void read(T &X) {
char ch = 0; T op = 1;
for (X = 0; ch > '9' || ch < '0'; ch = getchar())
if (ch == '-') op = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar())
X = (X * 10) + ch - '0';
X *= op;
}
namespace SegT {
struct Node {
int mxl, mnr, tag;
bool ok;
} s[N << 2];
inline void up(int p) {
mxl(p) = max(mxl(lc), mxl(rc));
mnr(p) = min(mnr(lc), mnr(rc));
ok(p) = ok(lc) & ok(rc) & (mxl(lc) <= mnr(rc));
}
inline void down(int p) {
if (!tag(p)) return;
mxl(lc) += tag(p), mnr(lc) += tag(p), tag(lc) += tag(p);
mxl(rc) += tag(p), mnr(rc) += tag(p), tag(rc) += tag(p);
tag(p) = 0;
}
void build(int p, int l, int r) {
tag(p) = 0;
if (l == r) {
mxl(p) = ln[l] + sum[l];
mnr(p) = rn[l] + sum[l];
ok(p) = mxl(p) <= mnr(p);
return;
}
build(lc, l, mid);
build(rc, mid + 1, r);
up(p);
}
Node query(int p, int l, int r, int x, int y) {
if (x <= l && y >= r) return s[p];
down(p);
if (y <= mid) return query(lc, l, mid, x, y);
else if (x > mid) return query(rc, mid + 1, r, x, y);
else {
Node resl = query(lc, l, mid, x, y);
Node resr = query(rc, mid + 1, r, x, y);
Node res;
res.mxl = max(resl.mxl, resr.mxl);
res.mnr = min(resl.mnr, resr.mnr);
res.ok = resl.ok & resr.ok & (resl.mxl <= resr.mnr);
return res;
}
}
void add(int p, int l, int r, int x, int y, ll v) {
if (x <= l && y >= r) {
mxl(p) += v;
mnr(p) += v;
tag(p) += v;
return;
}
down(p);
if (x <= mid) add(lc, l, mid, x, y, v);
if (y > mid) add(rc, mid + 1, r, x, y, v);
up(p);
}
void modify(int p, int l, int r, int x, ll vl, ll vr) {
if (l == r) {
mxl(p) += vl - ln[l];
mnr(p) += vr - rn[l];
ok(p) = mxl(p) <= mnr(p);
return;
}
down(p);
if (x <= mid) modify(lc, l, mid, x, vl, vr);
else modify(rc, mid + 1, r, x, vl, vr);
up(p);
}
} using namespace SegT;
int main() {
freopen("sample.in", "r", stdin);
clock_t st_clock = clock();
read(T);
for (; T--; ) {
read(n);
for (int i = 1; i <= n; i++) read(ln[i]);
for (int i = 1; i <= n; i++) read(rn[i]);
for (int i = 1; i < n; i++) read(d[i]);
sum[n] = d[n] = 0;
for (int i = n - 1; i >= 1; i--) sum[i] = sum[i + 1] + d[i];
build(1, 1, n);
read(qn);
for (int opt; qn--; ) {
read(opt);
if (opt == 0) {
int x, y;
read(x), read(y);
Node res = query(1, 1, n, x, y);
if (res.ok) puts("Yes");
else puts("No");
} else if (opt == 1) {
int p;
ll w;
read(p), read(w);
add(1, 1, n, 1, p, w - d[p]);
d[p] = w;
} else {
/* opt == 2 */
int p;
ll nl, nr;
read(p), read(nl), read(nr);
modify(1, 1, n, p, nl, nr);
ln[p] = nl, rn[p] = nr;
}
}
}
clock_t ed_clock = clock();
printf("time = %f ms\n", (double)(ed_clock - st_clock) / CLOCKS_PER_SEC * 1000);
return 0;
}