We apologize for both the late editorial and the statement leaking issues. Unfortunately, as the problem authors, we never had any chances to prevent the leaking. Still, feel free to downvote if you have dissatisfaction due to these.
But what so ever, we hope you can enjoy the problems.
Idea by Warriors_Cat
The method is simple: for $$$i = k, k - 1, \dots, 1$$$ successively, we adjust the courses at the $$$i$$$-th level of course wish one by one directly to the $$$(k+1)$$$-th level. It is easy to check that the adjustment is valid.
The number of steps is at most $$$nk \le 1000$$$.
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <cstdlib>
using namespace std;
#define ll long long
#define rep(i, x, y) for(int i = x; i <= y; ++i)
#define per(i, x, y) for(int i = x; i >= y; --i)
inline int read(){
int x = 0, f = 1; char ch = getchar();
while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); }
while(ch >= '0' && ch <= '9'){ x = x * 10 + (ch ^ 48); ch = getchar(); }
return x * f;
}
const int N = 55, M = 25, K = 1010;
int n, k, a[M], b[N], c[N];
int p[M][N], q[M][N], lenp[M], lenq[M];
int cnt, x[K], y[K];
inline void mian(){
memset(a, 0, sizeof(a)); memset(b, 0, sizeof(b));
memset(lenp, 0, sizeof(lenp));
n = read(); k = read();
rep(i, 1, k) a[i] = read();
rep(i, 1, n) b[i] = read(), p[b[i]][++lenp[b[i]]] = i;
cnt = 0;
per(i, k, 1){
int len = lenp[i];
rep(j, 1, len){
rep(l, i, k){
x[++cnt] = p[i][j];
}
}
}
printf("%d\n", cnt);
rep(i, 1, cnt) printf("%d ", x[i]);
puts("");
return;
}
int main(){ int qwq = read(); while(qwq--) mian(); return 0; }
Idea by E.Space
Combining T with U decreases $$$n$$$ by $$$2$$$. Combining T with H decreases $$$n$$$ by 1. One H can be inserted from both directions. Combining k rotated T's decreases $$$n$$$ by $$$k-1$$$. THUs, if $$$c_T \gt c_U+2c_H$$$, the answer will be $$$2c_T+3c_H+2c_U+1$$$; otherwise, the answer will be $$$2c_T+3c_H+3c_U-\min{c_T,c_U}$$$.
#include<bits/stdc++.h>
#define cmin(a,b) (a>(b)?a=(b),1:0)
#define cmax(a,b) (a<(b)?a=(b),1:0)
#define dmin(a,b) ((a)<(b)?(a):(b))
#define dmax(a,b) ((a)>(b)?(a):(b))
namespace io{
int F(){
int n=0,F=0;
char ch;
while((ch=getchar())!='-'&&(ch<'0'||ch>'9'));
ch=='-'?F=1:n=ch-'0';
while((ch=getchar())>='0'&&ch<='9')n=n*10+ch-'0';
return F?-n:n;
}
long long G(){
long long n=0,F=0;
char ch;
while((ch=getchar())!='-'&&(ch<'0'||ch>'9'));
ch=='-'?F=1:n=ch-'0';
while((ch=getchar())>='0'&&ch<='9')n=n*10+ch-'0';
return F?-n:n;
}
}
int main(){
int T=io::F();
while(T--){
long long t=io::F(),h=io::F(),u=io::F();
if(t>h*2+u){
printf("%lld\n",t*2+h*3+u*2+1);
}
else{
printf("%lld\n",t*2+h*3+u*3-dmin(t,u));
}
}
return 0;
}
Idea by Ecrade_
Each $$$a_i$$$ can only end up as either $$$b_i = a_i \bmod p$$$ or $$$c_i = (a_i \bmod q) \bmod p$$$.
We can see that except for the first chosen interval where all numbers must simultaneously become $$$b_i$$$ or simultaneously become $$$c_i$$$, all other numbers can become $$$\min(b_i, c_i)$$$.
Greedily, it is never worse to choose the first interval to have length exactly $$$k$$$. Enumerate all intervals of length $$$k$$$, compute the result, and take the minimum. The final answer is:
Using prefix sums for preprocessing, the time complexity is $$$\mathcal{O}(n)$$$.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll t,n,k,p,q,a[100009],f[100009][2],g[100009];
inline ll read(){
ll s = 0,w = 1;
char ch = getchar();
while (ch > '9' || ch < '0'){ if (ch == '-') w = -1; ch = getchar();}
while (ch <= '9' && ch >= '0') s = (s << 1) + (s << 3) + (ch ^ 48),ch = getchar();
return s * w;
}
int main(){
t = read();
while (t --){
ll ans = 1e18;
n = read(),k = read(),p = read(),q = read();
for (ll i = 1;i <= n;i += 1) a[i] = read();
for (ll i = 1;i <= n;i += 1) f[i][0] = a[i] % p % q,f[i][1] = a[i] % q % p;
for (ll i = 1;i <= n;i += 1) g[i] = g[i - 1] + min(f[i][0],f[i][1]);
for (ll i = 1;i <= n;i += 1) f[i][0] += f[i - 1][0],f[i][1] += f[i - 1][1];
for (ll i = k;i <= n;i += 1) ans = min(ans,min(f[i][0] - f[i - k][0],f[i][1] - f[i - k][1]) + g[i - k] + g[n] - g[i]);
printf("%lld\n",ans);
}
return 0;
}
Idea by SpiritualKhorosho
Divide the situations based on $$$k$$$:
$$$k=2$$$: $$$n=\sum\limits_{i=1}^{m}b^{i-1}(b+1)p_i$$$ must be a multiple of $$$b+1$$$, so enumerate factor of $$$n$$$.
$$$k\ge 3$$$: Similarly we can know $$$(b^{k-1}+\cdots+b+1)|n$$$,which implies $$$b\le \sqrt[k-1]{n}$$$,so enumerate $$$b$$$.
Time complexity is $$$O\left(\sqrt{n}\right)$$$
#include <cstdio>
using namespace std;
int check(long long n, long long b, int p) {
while (n) {
long long r = n % b;
n /= b;
for (int i = 1; i < p; ++i) {
if (n % b != r) return 0;
n /= b;
}
}
return 1;
}
int main(){
long long n, sum, pow;
int T, i, j, k, ans;
scanf("%d", &T);
while (T--) {
scanf("%lld", &n);
if (n <= 2) {
puts("0");
continue;
}
ans = 1;
if ((n & 1) == 0 && n >= 8) ans = 2;
for (i = 3; 1ll * i * i < n; ++i) {
if (n % i == 0) {
ans += check(n, i — 1, 2);
ans += check(n, 1ll * n / i — 1, 2);
}
}
if (1ll * i * i == n) ans += check(n, i — 1, 2);
for (i = 3; i <= 63; ++i) {
for (j = 2; j <= 1000000; ++j) {
sum = pow = 1;
for (k = 1; k < i; ++k) {
pow *= j;
sum += pow;
if (sum > n) break;
}
if (sum > n) break;
if (n % sum == 0) ans += check(n, j, i);
}
if (j == 2) break;
}
printf("%d\n", ans);
}
return 0;
}
Idea by dapingguo8
There are $$$2^{n-1}$$$ ways to direct the edges, which equals to the number of possible values of $$$s$$$. This implies we must find a strategy to deliver information from the very beginning, even there's little information about $$$T$$$ we can know.
Note that indexes of nodes persist, so consider direct the edges in two ways. Suppose $$$(a,b)$$$ is an undirected edge in $$$T$$$ and $$$a \lt b$$$:
- Assign direction $$$a\rightarrow b$$$. We'll call this edge a black edge.
- Assign direction $$$b\rightarrow a$$$. We'll call this edge a red edge.
Edges can be uncertain from the start, so consider utilize nodes to deliver information. Let's map the binary form of $$$s$$$ to nodes indexed $$$2$$$ to $$$n$$$, so each of these nodes has a number either $$$0$$$ or $$$1$$$ on it (and suppose node $$$1$$$ has $$$0$$$ written on it). When we acquire an undirected edge $$$(a,b)$$$ of $$$T$$$, if node $$$a$$$ and node $$$b$$$ have different number written on it, then direct the edge as red, and vice versa.
And for the second run, it's easy to deduce the numbers on each node by a simple DFS to recover $$$s$$$.
#include <bits/stdc++.h>
#define all(s) s.begin(), s.end()
using namespace std;
using ll = long long;
using ull = unsigned long long;
void Alice() {
int n; ll s; cin >> n >> s;
s -= 1;
vector<bool> special(n + 1, false);
for (int i = 2; i <= n; i++) special[i] = (s >> (i - 2)) & 1;
for (int i = 1; i < n; i++) {
int u, v; cin >> u >> v;
if (u > v) swap(u, v);
if (special[u] ^ special[v]) swap(v, u);
cout << u << ' ' << v << endl;
}
return;
}
void Bob() {
int n; cin >> n;
vector<vector<pair<int, int>>> g(n + 1, vector<pair<int, int>>());
for (int i = 1; i < n; i++) {
int u, v; cin >> u >> v;
int c = (u > v);
g[u].push_back({v, c});
g[v].push_back({u, c});
}
vector<bool> special(n + 1, false);
auto dfs = [&](auto self, int u, int f) -> void {
for (auto e : g[u]) {
int v = e.first, c = e.second;
if (v == f) continue;
if (c) special[v] = special[u] ^ 1;
else special[v] = special[u];
self(self, v, u);
}
};
dfs(dfs, 1, 0);
ll s = 0;
for (int i = 2; i <= n; i++) {
if (special[i]) s |= (1 << (i - 2));
}
cout << s + 1 << endl;
}
int main() {
ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
int t, q; cin >> t >> q;
while (t--) {
if (q == 1) Alice();
else Bob();
}
}
2215D - EXPloration, EXPloitation, and Gain Some EXPerience!
Idea by xiaoziyao
We can identify a key strategy: if player A leads player B by a sufficiently large margin, A can make three consecutive moves of distance $$$1$$$ to occupy four consecutive positions. This effectively blocks B from reaching any position beyond A's current location.
Specifically, suppose it is the leading player A's turn, with A at position $$$u$$$ and B at position $$$v$$$, where $$$u - v \geqslant 6$$$. In this case, A can force a block on B using a state sequence like the following (taking $$$v = u-6$$$ as an example): $$$(u-6,u) \to (u-6,u+1) \to (u-2,u+1) \to (u-2,u+2) \to (u-1,u+2) \to (u-1,u+3)$$$.
This constitutes the optimal strategy for both sides. Player A can guarantee that the final score difference is at most the value achieved in this scenario, because once B is blocked, A is guaranteed to claim all remaining positions in the suffix. Conversely, player B can guarantee that the score difference is at least this value, since regardless of how A plays, B can secure all positions in this intermediate segment.
Consequently, we can solve the problem using a backward DP. The state needs to track the position of the leading player, the distance gap $$$\in [0,5]$$$ between them, and a $$$2^4$$$ bitmask to record the occupancy status of the positions between the two players. This yields an $$$O(n)$$$ time complexity, and space complexity is easily manageable using rolling array optimization.
During implementation, note that after making a move, the leading player might temporarily extend their lead to a distance of $$$\geqslant 6$$$. However, on the subsequent turn, they will either move back to reduce the gap, or the situation will naturally fall into the blocking case described above.
#include<bits/stdc++.h>
using namespace std;
const int maxn=200005,maxs=(1<<4)+5;
int T,n;
int a[maxn];
long long sum[maxn];
long long f[2][5][maxn][maxs];
bool g[2][5][maxn][maxs];
long long dfs(int dir,int fr,int bk,int S){
int hav=0;
if(fr<n)
hav=1;
for(int i=bk+1;i<=n&&i<=bk+4;i++)
if(((S>>(i-bk-1))&1)==0&&i!=fr)
hav=1;
if(hav==0)
return 0;
if(fr-bk>=6&&dir==0){
long long res=sum[n]-sum[fr];
for(int i=bk+1;i<=fr-1;i++)
if(((S>>(i-bk-1))&1)==0)
res-=a[i];
return res;
}
if(fr-bk<6&&g[dir][fr-bk-1][bk][S])
return f[dir][fr-bk-1][bk][S];
long long res=-1e18;
if(dir==0){
int flg=0;
for(int i=fr+1;i<=n&&i<=fr+4;i++)
flg=1,res=max(res,a[i]-dfs(1,i,bk,S|(1<<(fr-bk-1))));
if(flg==0)
res=-dfs(1,fr,bk,S);
}
else{
int flg=0;
for(int i=bk+1;i<=n&&i<=bk+4;i++)
if(((S>>(i-bk-1))&1)==0&&i!=fr){
flg=1;
if(i<fr)
res=max(res,a[i]-dfs(0,fr,i,S>>(i-bk)));
if(i>fr)
res=max(res,a[i]-dfs(1,i,fr,0));
}
if(flg==0)
res=-dfs(0,fr,bk,S);
}
if(fr-bk<6)
f[dir][fr-bk-1][bk][S]=res,g[dir][fr-bk-1][bk][S]=1;
return res;
}
int main(){
memset(g,0,sizeof(g));
scanf("%d",&T);
while(T--){
scanf("%d",&n);
for(int i=3;i<=n;i++)
scanf("%d",&a[i]),sum[i]=sum[i-1]+a[i];
for(int i=n;i>=1;i--)
for(int j=i-1;j>=1&&j>=i-5;j--)
for(int k=0;k<=1;k++)
for(int s=0;s<(1<<(i-j-1));s++)
dfs(k,i,j,s);
printf("%lld\n",dfs(1,2,1,0));
for(int i=0;i<=1;i++)
for(int j=0;j<=4;j++)
for(int k=0;k<=n;k++)
for(int s=0;s<maxs;s++)
g[i][j][k][s]=0;
}
return 0;
}
Idea by Kratrissa
Consider the planar graph corresponding to the triangulation. Let the number of points on its outermost face be $$$x$$$, and the size of the triangulation be $$$t$$$. By Euler's formula for planar graphs, we have $$$V+F-E=1$$$. Together with $$$F\ge t$$$ and $$$E= \dfrac{3F+x}2$$$, we obtain $$$t\le F=2(n-1)-x$$$. The problem thus reduces to minimizing this $$$x$$$ and achieving equality simultaneously.
We now identify which points must lie on the outermost face. Intuitively, if, when taking a point as the origin, there exists a quadrant containing no other points, then this point must be on the convex hull (outer face). We next give a construction under which all equalities hold.
Sort all points by their $$$y$$$-coordinate in increasing order and add them one by one, while maintaining two monotonic stacks $$$q_1,q_2$$$ satisfying: $$$x_{q_{1,i}} \gt x_{q_{1,i-1}},\ y_{q_{1,i}} \gt y_{q_{1,i-1}}$$$; $$$x_{q_{2,i}} \lt x_{q_{2,i-1}},\ y_{q_{2,i}} \gt y_{q_{2,i-1}}$$$, and the top elements of the two stacks are identical.
When inserting a point $$$(x_i,y_i)$$$, update the two stacks as follows:
If $$$q_1$$$ is nonempty, take its top element $$$j$$$. If $$$x_i \lt x_j$$$, pop $$$j$$$ from the stack; if the stack is still nonempty, let $$$k$$$ be its new top, and add $$$(i,j,k)$$$ to $$$T$$$. Repeat until $$$x_i \gt x_j$$$.
If $$$q_2$$$ is nonempty, take its top element $$$j$$$. If $$$x_i \gt x_j$$$, pop $$$j$$$ from the stack; if the stack is still nonempty, let $$$k$$$ be its new top, and add $$$(i,j,k)$$$ to $$$T$$$. Repeat until $$$x_i \lt x_j$$$.
It can be easily verified that this construction achieves equality.
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int T, n, ql[N], qr[N], tpl, tpr, cnt;
struct point {
int x, y, id;
bool operator<(const point &other) const {
return y < other.y;
}
} p[N];
struct triangle { int a, b, c; } ans[N << 1];
int main() {
scanf("%d", &T);
while (T--) {
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d%d", &p[i].x, &p[i].y), p[i].id = i;
sort(p + 1, p + n + 1);
cnt = 0;
ql[1] = qr[1] = 1;
tpl = tpr = 1;
for (int i = 2; i <= n; i++) {
while (tpl && p[i].x < p[ql[tpl]].x) {
if (tpl >= 2) ans[++cnt] = triangle{p[i].id, p[ql[tpl]].id, p[ql[tpl - 1]].id};
tpl--;
}
ql[++tpl] = i;
while (tpr && p[i].x > p[qr[tpr]].x) {
if (tpr >= 2) ans[++cnt] = triangle{p[i].id, p[qr[tpr]].id, p[qr[tpr - 1]].id};
tpr--;
}
qr[++tpr] = i;
}
printf("%d\n", cnt);
for (int i = 1; i <= cnt; i++)
printf("%d %d %d\n", ans[i].a, ans[i].b, ans[i].c);
}
return 0;
}
Idea by E.Space
The game cannot go on indefinitely. When $$$n \le k$$$, Alice must end the game immediately; otherwise, Bob will remove the green card on the next turn, making the score $$$0$$$. Moreover, Bob can continuously remove cards to make the deck thinner. Therefore, Bob has the ability to prevent Alice from continuing the game indefinitely.
First, consider the case where $$$s=1$$$. In this situation, Alice must decide whether to take the green card or put it back. Once she puts it back, who gets the green card next only depends on its position. It can be observed that only when $$$n \equiv k \pmod{2k}$$$, regardless of how Alice puts it back, she cannot get the green card next time. In this case, it is clearly optimal to remove the green card directly; otherwise, Alice can always find a way to ensure she gets the green card next time by placing it either before or after all the other removed cards. Thus, putting it back is definitely better than removing it directly.
Starting from Alice putting the green card back, both players will perform $$$x = \left\lfloor \frac{n+k}{2k} \right\rfloor$$$ operations, after which it will again become a situation where Alice can take the green card. The key question is how much the size of the pile will change.
Let $$$f_k(n)$$$ be the final score when the pile size is $$$n$$$, $$$s=1$$$, and $$$k=k$$$. In each subsequent operation, both players can choose to remove a card or not. We can prove that the final score will be $$$1 + \max\left(\min{f_k(n-x-1), f_k(n-x)}, \min{f_k(n-x), f_k(n-x+1)}\right)$$$. Alternatively, it can be expressed as $$$1 + \min(\max{f_k(n-x-1), f_k(n-x+1)}, f_k(n-x))$$$.
There are a total of $$$2x$$$ operations, which may remove between $$$0$$$ and $$$2x$$$ cards. We can shift the coordinate system to consider that, in the end, there will be $$$n-x$$$ cards left. When one person removes a card, it is equivalent to reducing the pile by $$$0.5$$$ cards, while not removing it increases the pile by $$$0.5$$$ cards. For Alice, she can choose to move $$$0.5$$$ steps left or right on her first move, and then let Bob choose one of the two adjacent options. Bob can always ensure he picks the smaller of the two, as long as all his subsequent moves are the opposite of Alice's. Thus, the final score will be less than or equal to this. Conversely, Alice can ensure that the score is greater than or equal to the smaller of the two options because she can make Bob make the same choice each time. Therefore, the answer must be this. However, there is a special case: when $$$n \equiv k+1 \pmod{2k}$$$, Alice must not remove the card and must place the green card at the bottom of the pile to ensure she can take it next time. Thus, in this case, Alice's first move can only be to move right, and the answer becomes $$$1 + \min\left( f_k(n - \left\lfloor \frac{n+k}{2k} \right\rfloor), f_k(n - \left\lfloor \frac{n+k}{2k} \right\rfloor + 1) \right)$$$.
Next, this problem has an interesting property (which I discovered through tabulation): when $$$f_k(n-1) \lt f_k(n) \gt f_k(n+1)$$$, it must be that $$$n \equiv k-1 \pmod{2k}$$$. The proof is not difficult. Consider segmenting based on $$$n \equiv k \pmod{2k}$$$. For the case where $$$n-1, n, n+1$$$ are in the same segment (i.e., not including points where these values are $$$1$$$), let $$$f_k(n-1) = \max{[m_{12},] m_{23}}, f_k(n) = \max{m_{23}, m_{34}}, f_k(n+1) = \max{m_{34}, m_{45}}$$$. Here, $$$m_{ij}$$$ represents the minimum value of two adjacent terms of $$$f_k$$$ plus $$$1$$$. If $$$m_{23} \ge m_{34}$$$, then $$$f_k(n-1) \ge f_k(n)$$$ (regardless of whether the term $$$m_{12}$$$ exists), and if $$$m_{23} \lt m_{34}$$$, then $$$f_k(n+1) \ge f_k(n)$$$. When $$$n \equiv k+1$$$, $$$f_k(n-1) = 1, f_k(n) = m_{34}, f_k(n+1) = \max{m_{34}, m_{45}} \ge f_k(n)$$$. When $$$n \equiv k$$$, $$$f_k(n) = 1$$$ will certainly not be greater than the two sides. Therefore, when $$$f_k(n-1) \lt f_k(n) \gt f_k(n+1)$$$, it must be that $$$n \equiv k-1 \pmod{2k}$$$. At this point, $$$f_k(n+1) = 1$$$.
Thus, as long as it is not one of the three cases $$$n \equiv k, n \equiv k+1, n-x \equiv k-1$$$, we have $$$f_k(n) = f_k(n-x) + 1$$$. For the third case, since $$$f_k(n-x-1)$$$ must be greater than or equal to $$$f_k(n-x+1) = 1$$$, it can be expressed as $$$1 + \min\left( f_k(n - \left\lfloor \frac{n+k}{2k} \right\rfloor), f_k(n - \left\lfloor \frac{n+k}{2k} \right\rfloor - 1) \right)$$$. Thus, we have the following recurrence relation:
Note that when $$$k$$$ is relatively large, $$$x$$$ is quite small, so for the last case, we can speed up at the same $$$x$$$. That is, consider jumping continuously $$$\left\lfloor \frac{(n+k) \bmod 2k}{x} \right\rfloor$$$ steps. Clearly, this will not pass through the first three cases. If this value is $$$0$$$, then we just make one step normally.
Next, consider the case where $$$s \ne 1$$$. In other words, as the green card surfaces, both players still need to perform $$$x = \left\lfloor \frac{s-1}{2k} \right\rfloor$$$ operations. Thus, according to the previous analysis, the answer is $$$\min{\max{f_k(n-x-1), f_k(n-x+1)}, f_k(n-x)}$$$.
The recurrence relation can be solved using memoization. Since when $$$n \equiv k$$$, it immediately returns $$$1$$$, and when $$$n \equiv k+1$$$, it will expand backward, encountering $$$n \equiv k-1$$$ will expand forward, so at each level, at most two states will be accessed. When $$$n \le (2k)^2$$$, we have $$$x \le 2k$$$, and because we accelerated the last line, there will only be $$$\min{n, (2k)^2} / 2k$$$ layers. When $$$n \gt (2k)^2$$$, each time $$$n$$$ will change to $$$\frac{2k-1}{2k}$$$ of its original value, resulting in $$$2k \max{0, \log(n/(2k)^2)}$$$ layers. The former reaches its maximum when $$$k = \sqrt{n}/2$$$, and the latter reaches its maximum when $$$k = \sqrt{n}/(2e)$$$, both being $$$O(\sqrt{n})$$$.
#include<bits/stdc++.h>
#define cmin(a,b) (a>(b)?a=(b),1:0)
#define cmax(a,b) (a<(b)?a=(b),1:0)
#define dmin(a,b) ((a)<(b)?(a):(b))
#define dmax(a,b) ((a)>(b)?(a):(b))
namespace io{
int F(){
int n=0,F=0;
char ch;
while((ch=getchar())!='-'&&(ch<'0'||ch>'9'));
ch=='-'?F=1:n=ch-'0';
while((ch=getchar())>='0'&&ch<='9')n=n*10+ch-'0';
return F?-n:n;
}
long long G(){
long long n=0,F=0;
char ch;
while((ch=getchar())!='-'&&(ch<'0'||ch>'9'));
ch=='-'?F=1:n=ch-'0';
while((ch=getchar())>='0'&&ch<='9')n=n*10+ch-'0';
return F?-n:n;
}
}
std::unordered_map<long long,long long> s;
long long k;
long long F(long long n){
if(n<3*k)return n-k+1;
long long& f = s[n];
if(f>0)return f;
if(n%(2*k)==k)return f=1;
long long x=(n+k)/(2*k);
if(n%(2*k)==k+1){
return f=std::min(F(n-x),F(n-x+1))+1;
}
else if((n-x)%(2*k)==k-1){
return f=std::min(F(n-x),F(n-x-1))+1;
}
else{
long long t = (n+k)-(2*k*x);
if(t>=x){
long long b=t/x;
return f=F(n-b*x)+b;
}
return f=F(n-x)+1;
}
}
int main(){
int T=io::F();
while(T--){
s.clear();
long long n=io::G();
k=io::G();
long long s=io::G();
if(n<=k){
puts("1");
continue;
}
if((s-1)%(2*k)>=k){
puts("0");
continue;
}
int x=(s-1)/(2*k);
if(x==0){
printf("%lld\n",F(n));
}
else{
long long v1=F(n-x-1),v2=F(n-x),v3=F(n-x+1);
if(v2>v1&&v2>v3){
printf("%lld\n",dmax(v1,v3));
}
else{
printf("%lld\n",v2);
}
}
}
return 0;
}
Idea By crazy_sea
First, we may assume without loss of generality that the cost of moving straight (up, down, left, right) is $$$1$$$, and the cost of moving diagonally is $$$\sqrt{2}$$$.
Let the final answer be $$$a+b\sqrt{2}$$$; we then output $$$2a+3b$$$, and it is easy to verify that this does not affect the correctness of the result.
Consider how to compute the answer under this assumption: direct calculation is nearly infeasible, but we can instead consider the answer in terms of projections. The problem guarantees that all obstacles form a single connected component and that the entire region is surrounded by obstacles on all sides.
Specifically, we can consider the length of the path's projection in a certain direction. We attempt to project onto four directions (up, right, upper-right, upper-left), then perform a linear combination of these projections. After doing so, the problem reduces to finding the distance between two nodes in a tree, which can be solved with a straightforward method.
The bottleneck of the algorithm lies in computing the distance between two nodes in the tree.
#include <bits/stdc++.h>
using namespace std;
inline int read()
{
int s=0,f=1;
char c=getchar();
while(c<'0'||c>'9')
{
if(c=='-')
f=-1;
c=getchar();
}
while(c>='0'&&c<='9')
{
s=s*10+c-'0';
c=getchar();
}
return s*f;
}
int lg[1000007];
inline void Init()
{
for(int i=1;i<=1000000;++i)
lg[i]=log2(i);
}
int n,m,q;
struct Point{
int x,y;
}p[300007];
inline bool cmp0(Point x,Point y)
{
if(x.x==y.x)
return x.y<y.y;
return x.x<y.x;
}
struct Node{
int x,l,r,id;
};
struct Tree{
vector <int> a[1000007];
Node d[1000007];
vector <int> c[1000007];
int cnt;
int depth[1000007],fa[1000007][21];
inline void dfs0(int x,int Fa)
{
depth[x]=depth[Fa]+1;
fa[x][0]=Fa;
for(int i=1;i<=lg[depth[x]];++i)
fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=0;i<a[x].size();++i)
{
int v=a[x][i];
if(v==Fa)
continue;
dfs0(v,x);
}
}
inline int LCA(int x,int y)
{
if(depth[x]<depth[y])
swap(x,y);
while(depth[x]>depth[y])
x=fa[x][lg[depth[x]-depth[y]]];
if(x==y)
return x;
for(int i=lg[depth[x]];i>=0;--i)
{
if(fa[x][i]!=fa[y][i])
x=fa[x][i],y=fa[y][i];
}
return fa[x][0];
}
inline int query_id(int x,int y)
{
int lca=LCA(x,y);
if(lca==0)
return -1;
return depth[x]+depth[y]-2*depth[lca];
}
inline void build(int id)
{
if(id==0||id==2)
{
if(id==2)
{
for(int i=1;i<=m;++i)
{
int x=p[i].x,y=p[i].y;
p[i].x=x+y;
p[i].y=x-y;
}
}
sort(p+1,p+m+1,cmp0);
int l1=1;
for(int i=1+(id==2);i<=n*(1+(id==2));++i)
{
++cnt;
d[cnt].x=i,d[cnt].id=cnt;
if(id==0)
d[cnt].l=1;
else
d[cnt].l=-min(i-2,2*n-i);
while(l1<=m&&p[l1].x==i)
{
if(p[l1].y==d[cnt].l)
d[cnt].l=p[l1].y+1;
else
{
d[cnt].r=p[l1].y-1,c[i].push_back(cnt);
++cnt;
d[cnt].x=i,d[cnt].l=p[l1].y+1,d[cnt].id=cnt;
}
++l1;
}
if(id==0)
{
if(d[cnt].l>n)
--cnt;
else
d[cnt].r=n,c[i].push_back(cnt);
}
else
{
if(d[cnt].l>min(i-2,2*n-i))
--cnt;
else
d[cnt].r=min(i-2,2*n-i),c[i].push_back(cnt);
}
}
for(int x=1+(id==2);x<n*(1+(id==2));++x)
{
int l1=0;
for(int i=0;i<c[x].size();++i)
{
while(l1<c[x+1].size()&&d[c[x+1][l1]].r<d[c[x][i]].l-(id==0))
++l1;
bool flag=0;
while(l1<c[x+1].size()&&d[c[x+1][l1]].l<=d[c[x][i]].r+(id==0))
{
a[c[x][i]].push_back(c[x+1][l1]);
a[c[x+1][l1]].push_back(c[x][i]);
++l1;
flag=1;
}
if(flag)
--l1;
}
}
for(int i=1;i<=cnt;++i)
{
if(!depth[i])
dfs0(i,0);
}
if(id==2)
{
for(int i=1;i<=m;++i)
{
int x=p[i].x,y=p[i].y;
p[i].x=(x+y)/2;
p[i].y=(x-y)/2;
}
}
}
else if(id==1)
{
for(int i=1;i<=m;++i)
swap(p[i].x,p[i].y);
build(0);
for(int i=1;i<=m;++i)
swap(p[i].x,p[i].y);
}
else if(id==3)
{
for(int i=1;i<=m;++i)
p[i].y=n+1-p[i].y;
build(2);
for(int i=1;i<=m;++i)
p[i].y=n+1-p[i].y;
}
}
inline int Query(int id,int sx,int sy,int tx,int ty)
{
int x=0,y=0;
if(id==0)
{
for(int i=0;i<c[sx].size();++i)
{
if(d[c[sx][i]].l<=sy&&sy<=d[c[sx][i]].r)
{
x=c[sx][i];
break;
}
}
for(int i=0;i<c[tx].size();++i)
{
if(d[c[tx][i]].l<=ty&&ty<=d[c[tx][i]].r)
{
y=c[tx][i];
break;
}
}
assert(x&&y);
return query_id(x,y);
}
else if(id==1)
{
return Query(0,sy,sx,ty,tx);
}
else if(id==2)
{
return Query(0,sx+sy,sx-sy,tx+ty,tx-ty);
}
else
{
return Query(2,sx,n+1-sy,tx,n+1-ty);
}
}
}tree[4];
int main()
{
Init();
n=read(),m=read(),q=read();
for(int i=1;i<=m;++i)
p[i].x=read(),p[i].y=read();
for(int i=0;i<4;++i)
tree[i].build(i);
int sx,sy,tx,ty;
while(q--)
{
sx=read(),sy=read(),tx=read(),ty=read();
int ans=0;
for(int i=0;i<4;++i)
{
ans+=tree[i].Query(i,sx,sy,tx,ty)*(1+(i<2));
if(ans==-2)
{
assert(i==0);
break;
}
}
ans/=2;
printf("%d\n",ans);
}
return 0;
}









Ragebaitforces
I created video editorial for C. Interval Mod and video editorial for D. RReeppeettiittiioonn
Thanks for the editorial. Pretty impressed by solution D, especially the last few lines were an eye-opener regarding the max distance to be considered and thus, the no. of masks.
During implementation, note that after making a move, the leading player might temporarily extend their lead to a distance of ⩾ 6. However, on the subsequent turn, they will either move back to reduce the gap, or the situation will naturally fall into the blocking case described above.
Great problemset indeed, unfortunate that it was an unrated contest. But it is something that the contest setters would find tough to control. Kudos!
1.I solved problem 1B in $$$O(d(n)+n^{1/3})$$$ on the contest, ignoring the condition $$$\sum n\le10^{12}$$$.
2.I thought that 1D/2F maybe the players won't be very far, but didn't notice that when dis>=6 A will get all of the score.
3.The problems 1D and 1E are so ad-hoc!!
The F problem solution can be easier. You can use the Monotonic Stack. Just use two stacks, a monotonic increasing stack and a monotonic decreasing stack, it's easier than the solution in the editorial.
Problem G, is there a more formal proof, or a more detailed proof?
I solved it in what I think is the intended way (by considering the projections and using 4 trees). Here is a more detailed and understandable proof/solution:
Let $$$\mathbf{A}$$$ = minimum cost if we can move orthogonally with a cost of $$$1$$$ and diagonally with a cost of $$$2$$$ ($$$\mathbf{A}$$$ = the number of orthogonal moves, if an orthogonal path exists)
Let $$$\mathbf{B}$$$ = minimum cost if we can move orthgonally or diagonally with a cost of $$$1$$$ ($$$\mathbf{B}$$$ = the number of chess king moves)
Let $$$\mathbf{C}$$$ = minimum cost if we can move orthogonally with a cost of $$$2$$$ and diagonally with a cost of $$$3$$$ (the solution we are looking for)
Then $$$\mathbf{A} + \mathbf{B} = \mathbf{C}$$$, since both $$$\mathbf{A}$$$'s and $$$\mathbf{B}$$$'s paths coincide with $$$\mathbf{C}$$$'s path. A proof of this fact can be derived from the statement in your comment: "It is optimal to visit the vertices (intervals) of this tree in order". This would also be the way to prove the intended solution's statement: we can replace $$$2, 3$$$ with $$$1, \sqrt{2}$$$.
To compute $$$\mathbf{A}$$$, we construct 2 trees using the 8-neighbor relation (as you mentioned in your comment) and add up the lengths of the paths (one of the lengths is the x projection and the other is the y projection). (Note: If we had constructed the trees with the 4-neighbor relation, $$$\mathbf{A}$$$ would be the genuine orthogonal distance)
To compute $$$\mathbf{B}$$$, we transform the grid with the matrix:
(This matrix does: 45 degree clockwise rotation, followed by a flip about the x axis and a scaling by $$$\sqrt{2}$$$.)
Because 2 orthogonal moves in this transformed grid correspond to 1 (chess king) move in the original grid, we construct a simillar tree, only this time using only the 4-neighbor relation (to prevent diagonal moves). Then after querying the distance, we need to divide by 2.
Here is my implementation: 377032285
Edit: the complexity of this algorithm is $$$\mathcal{O}(X * log(X) + q * log(X))$$$, where $$$\mathbf{X} = \mathbf{m} + 4 * \mathbf{n}$$$ is the number of blocked cells
Solution Explanation
Observation 1
First, let us assume that we are asked for the Euclidean distance (ignoring complexity for now). We note that the shortest path under the Euclidean metric is unique.
An intuitive way to understand this is to imagine drilling a hole at the start and end points in the maze, then threading a string through these two holes, connecting the start and end points inside the maze. If we pull both ends of the string simultaneously, the resulting taut string corresponds exactly to the shortest path.
Observation 2
Under an affine transformation, the Euclidean shortest path maps to the Euclidean shortest path of the transformed maze.
Formally, let $$$F$$$ be a linear coordinate transformation, let $$$M$$$ be the corresponding maze with its start and end points, and let $$$S(M)$$$ denote the shape of the Euclidean shortest path in $$$M$$$. Then we have
The same physical string model can be used to understand this property.
Observation 3
In fact, the query can be interpreted as the Manhattan distance plus the Chebyshev distance between the start and end points.
If we take the grid to the infinitesimal limit, the shape of the Manhattan shortest path and the shape of the Chebyshev shortest path both coincide with the shape of the Euclidean shortest path.
Algorithm
Therefore, we can directly compute the shortest distances along projections in four directions (vertical, horizontal, and the two diagonal directions), multiply each by the corresponding coefficient, and sum them up.
To compute the shortest path along one projection direction (take the vertical direction as an example), we can treat each maximal vertical segment without obstacles as a single node. The resulting graph then becomes a tree. Hence, the bottleneck of the algorithm is locating which node each point belongs to and computing LCA (Lowest Common Ancestor) queries.
The reference implementation uses Heavy-Light Decomposition (HLD) for LCA queries. It runs in approximately 0.5 seconds, and the code length is about 4 KB.
Problem G.
I solved it. However, I was not able to intuitively understand the editorial well, nor was I able to prove it properly. So, for anyone who may feel similarly, I will briefly write down my solution.
Consider $$$O(n+m)$$$ intervals of the form $$$[x,x] \times [y_1,y_2]$$$, and build a tree using the 8-neighbor relation. It is optimal to visit the vertices (intervals) of this tree in order. This can be shown by considering the shortest distance between two points within the same vertex.
First, there is an $$$O(\text{path length})$$$ solution. We move through the vertices one by one while updating a function $$$dp_v(y)$$$. The update of $$$dp_v(y)$$$ can be expressed as a min-plus convolution with a function $$$[\ldots,9,7,5,3,2,3,5,7,9,\ldots]$$$, together with a restriction of the domain.
From this, we can see that $$$dp_v(y)$$$ is a convex function whose slopes consist of $$$-2,-1,0,1,2$$$. Therefore, $$$dp_v(y)$$$ can be described by four integers representing the "slope-change points", together with its minimum value.
These four types of slope-change points can be handled independently. The computation along a tree path can be aggregated by composing functions consisting of operations such as add, chmax, and chmin.
The minimum value of the dp function can also be decomposed into separate computations for each of the four types of slope-change points. Adding a contribution whenever a slope-change point on the negative-slope side is affected by chmin, or a slope-change point on the positive-slope side is affected by chmax.
In the end, the problem decomposes into four computations of the following type along a tree path: repeatedly apply add, chmax, and chmin, and compute the total amount moved by the chmax and chmin operations. This is a well-known type of problem that can be handled by a segment tree or similar data structure, since it forms a monoid.
why if cT>cU+2cH, not just cT>cU?
can anyone explain how Question INTERVAL MOD solution works fine ?
like let we got the that segment which causes min penalty ,now what we are doing ?
setting that interval first and then expanding left and right or first expanding left and right and then setting the interval in the last ,
how we are doing this ?
I think yours 2216A little bit complicated here
The first one ain't 900 bro, at least 1100
or even 1300 because, i have solved 1500 rated problems and they are so easy compared to this