T1
Description
给你一棵 \(n\) 个点的树和 \(q\) 个询问。每次询问给出 \(a,d_a,b,d_b\),要你找到任意一个满足 \(dist(a,u)=d_a\) 且 \(dist(b,u)=d_b\) 的点 \(u\)。找不到输出 \(-1\)。
\(1\leq n,q\leq 10^6\)。时空限制 \(5s/512MB\)。
Solution
要先实现一个函数 \(calc(x,y,d)\) 找到路径 \(x→y\) 上到 \(x\) 的距离为 \(d\) 的点。找不到返回 \(-1\)。令 \(z=lca(x,y)\),若 \(d\leq dist(x,z)\),则 \(ans=jump(x,d)\),否则 \(ans=jump(y,dist(x,y)-d)\)。其中 \(jump(x,d)\) 表示 \(x\) 的 \(d\) 级祖先,可以用倍增实现。
接下来,设 \(c=lca(a,b)\),分 \(4\) 种情况讨论。
- \(u\) 在 \(a\) 子树中。要满足 \(d_a+dist(a,b)=d_b\)。找到 \(u\) 子树中最深的节点 \(v\),\(ans=calc(u,v,d_a)\)。
- \(u\) 在 \(b\) 子树中,同理。
- \(u\) 在路径 \(a→b\) 上某个点 \(y\) 的子树里,\(y≠a,y≠b\)。此时要满足 \(d_a+d_b\geq dist(a,b)\),然后有: \(dist(a,y)+dist(b,y)=dist(a,b),d_a-d_b=dist(a,y)-dist(b,y)\)。可以解出 \(dist(a,y)\) 从而找到 \(y\),注意如果解出的 \(dist(a,y)\) 不是整数,无解。接下来,若 \(y≠c\),设 \(y\) 在 \(a→b\) 路径上的子节点为 \(x\)。找到子树 \(y\) 中除了子树 \(x\) 以外的最深点 \(t\),\(ans=calc(y,t,d_a-dist(a,y))\)。若 \(y=c\),\(y\) 在 \(a→b\) 路径上的子节点有两个,同样处理即可。记 \(Max(u)\) 为 \(u\) 这个子树中最深的点的深度,那么需要预处理出每个点 \(Max\) 最大的 \(3\) 个子节点,以及每个点的子树中最深的点是哪个。
- \(u\) 在子树 \(c\) 外,需要满足 \(d_a-d_b=dist(a,c)-dist(b,c),d_a+d_b\geq dist(a,b)\)。设子树 \(c\) 外离 \(c\) 最远的点是 \(g_c\),那么 \(ans=calc(c,g_c,d_a-dist(a,c))\)。\(g\) 用换根 \(\text{dp}\) 预处理即可。
时间复杂度 \(O(n\log n)\)。
Code
#include <bits/stdc++.h>
using namespace std;
#define ll long long
template <class t>
inline void read(t & res)
{
char ch;
while (ch = getchar(), !isdigit(ch));
res = ch ^ 48;
while (ch = getchar(), isdigit(ch))
res = res * 10 + (ch ^ 48);
}
template <class t>
inline void print(t x)
{
if (x < 0)
{
putchar('-');
x = ~x + 1;
}
if (x > 9) print(x / 10);
putchar(x % 10 + 48);
}
const int e = 1e6 + 5, o = e << 1;
int a[e], b[e], dep[e], n, q, num, nxt[o], go[o], adj[e], c[e], d[e], pos[o], cnt,
logn[o], st[o][21], g[e];
int dfn[e], f[e][20], ans, s3[e], t3[e];
inline void add(int x, int y)
{
nxt[++num] = adj[x]; adj[x] = num; go[num] = y;
nxt[++num] = adj[y]; adj[y] = num; go[num] = x;
}
inline void dfs1(int u, int pa)
{
dfn[u] = ++cnt;
dep[u] = dep[pa] + 1;
pos[cnt] = u; a[u] = b[u] = c[u] = d[u] = u;
int i;
for (i = 0; i < 19; i++) f[u][i + 1] = f[f[u][i]][i];
for (i = adj[u]; i; i = nxt[i])
{
int v = go[i];
if (v == pa) continue;
f[v][0] = u;
dfs1(v, u);
pos[++cnt] = u;
if (dep[c[v]] > dep[c[u]])
{
t3[u] = d[u];
d[u] = c[u];
c[u] = c[v];
s3[u] = b[u];
b[u] = a[u];
a[u] = v;
}
else if (dep[c[v]] > dep[d[u]])
{
t3[u] = d[u];
d[u] = c[v];
s3[u] = b[u];
b[u] = v;
}
else if (dep[c[v]] > dep[t3[u]])
{
t3[u] = c[v];
s3[u] = v;
}
}
}
inline void init()
{
int i, j;
logn[0] = -1;
for (i = 1; i <= cnt; i++)
{
logn[i] = logn[i >> 1] + 1;
st[i][0] = pos[i];
}
for (j = 1; (1 << j) <= cnt; j++)
for (i = 1; i + (1 << j) - 1 <= cnt; i++)
{
int u = st[i][j - 1], v = st[i + (1 << j - 1)][j - 1];
if (dep[u] < dep[v]) st[i][j] = u;
else st[i][j] = v;
}
}
inline int lca(int l, int r)
{
l = dfn[l]; r = dfn[r];
if (l > r) swap(l, r);
int k = logn[r - l + 1], u = st[l][k], v = st[r - (1 << k) + 1][k];
return dep[u] < dep[v] ? u : v;
}
inline int dist(int x, int y)
{
int z = lca(x, y);
return dep[x] + dep[y] - (dep[z] << 1);
}
inline int jump(int x, int d)
{
for (int i = 19; i >= 0; i--)
if (d & (1 << i)) x = f[x][i];
return x;
}
inline int calc(int x, int y, int d)
{
int z = lca(x, y), dis = dep[x] + dep[y] - (dep[z] << 1);
if (d <= dep[x] - dep[z]) return jump(x, d);
else return jump(y, dis - d);
}
inline void dfs2(int u, int pa)
{
int i;
for (i = adj[u]; i; i = nxt[i])
{
int v = go[i];
if (v == pa) continue;
g[v] = g[u];
if (a[u] == v)
{
if (dist(d[u], v) > dist(g[v], v)) g[v] = d[u];
}
else
{
if (dist(c[u], v) > dist(g[v], v)) g[v] = c[u];
}
dfs2(v, u);
}
}
inline int solve12(int u, int v, int du, int dv, int z)
{
int dis = dep[u] + dep[v] - (dep[z] << 1);
if (dv == du + dis)
{
if (z == u)
{
int fv = calc(u, v, 1);
if (fv != a[u])
{
if (dep[c[u]] - dep[u] >= du) return calc(u, c[u], du);
}
else if (dep[d[u]] - dep[u] >= du) return calc(u, d[u], du);
}
else if (dep[c[u]] - dep[u] >= du) return calc(u, c[u], du);
}
if (du == dv + dis)
{
if (z == v)
{
int fu = calc(v, u, 1);
if (fu != a[v])
{
if (dep[c[v]] - dep[v] >= dv) return calc(v, c[v], dv);
}
else if (dep[d[v]] - dep[v] >= dv) return calc(v, d[v], dv);
}
else if (dep[c[v]] - dep[v] >= dv) return calc(v, c[v], dv);
}
return -1;
}
inline int solve3(int u, int v, int du, int dv, int z)
{
int dis = dep[u] + dep[v] - (dep[z] << 1);
if (du + dv >= dis)
{
int del = du - dv;
if ((dis + del) & 1) return -1;
int a1 = dis + del >> 1, b1 = dis - a1, y = calc(u, v, a1), tot = du - a1;
if (a1 < 0 || b1 < 0) return -1;
if (y == u || y == v) return -1;
if (y == z)
{
int fu = jump(u, dep[u] - dep[z] - 1), fv = jump(v, dep[v] - dep[z] - 1);
if (a[z] != fu && a[z] != fv)
{
if (dep[c[z]] - dep[z] >= tot) return calc(z, c[z], tot);
}
else if (b[z] != fu && b[z] != fv)
{
if (dep[d[z]] - dep[z] >= tot) return calc(z, d[z], tot);
}
else
{
if (dep[t3[z]] - dep[z] >= tot) return calc(z, t3[z], tot);
}
}
else if (a1 <= dep[u] - dep[z])
{
int ys = calc(u, v, a1 - 1);
if (ys == a[y])
{
if (dep[d[y]] - dep[y] >= tot) return calc(y, d[y], tot);
}
else
{
if (dep[c[y]] - dep[y] >= tot) return calc(y, c[y], tot);
}
}
else
{
int ys = calc(u, v, a1 + 1);
if (ys == a[y])
{
if (dep[d[y]] - dep[y] >= tot) return calc(y, d[y], tot);
}
else
{
if (dep[c[y]] - dep[y] >= tot) return calc(y, c[y], tot);
}
}
}
return -1;
}
inline int solve4(int u, int v, int du, int dv, int z)
{
int dis = dep[u] + dep[v] - (dep[z] << 1);
if (du - dv == dep[u] - dep[v] && dep[u] - dep[z] <= du && dep[v] - dep[z] <= dv)
{
int dc = du - (dep[u] - dep[z]);
if (dist(z, g[z]) >= dc) return calc(z, g[z], dc);
}
return -1;
}
int main()
{
freopen("hunting.in", "r", stdin);
freopen("hunting.out", "w", stdout);
read(n); read(q);
int u, v, i, du, dv;
for (i = 1; i < n; i++) read(u), read(v), add(u, v);
dfs1(1, 0);
init();
g[1] = 1;
dfs2(1, 0);
while (q--)
{
read(u); read(du); read(v); read(dv);
if (u == v && du != dv)
{
puts("-1");
continue;
}
ans = -1;
if (u == v)
{
if (dist(u, g[u]) >= du) ans = calc(u, g[u], du);
else if (dist(u, c[u]) >= du) ans = calc(u, c[u], du);
print(ans); putchar('\n');
continue;
}
int z = lca(u, v);
ans = solve12(u, v, du, dv, z);
if (ans == -1) ans = solve3(u, v, du, dv, z);
if (ans == -1) ans = solve4(u, v, du, dv, z);
print(ans); putchar('\n');
}
fclose(stdin);
fclose(stdout);
return 0;
}
T2
Description
给定一张 \(n\) 个点 \(m\) 条边的无向图,求有多少个非空点集的导出子图连通。
导出子图:仅保留这个点集中的点和端点都在这个点集中的边。
无向图的边 \((x,y)\) 都满足 \(|x-y|\leq 12\)。
答案对 \(2\) 取模,\(1\leq n\leq 50\),时空限制 \(2s/512MB\)。
Solution
导出子图连通也就是导出子图的连通块个数 \(=1\),否则连通块个数 \(>1\)。
发现在 \(mod\ 4\) 意义下,\(2^1=2,2^k=0(k>1)\)。
那么考虑求所有非空点集的导出子图的 \(2^{连通块个数}\) 之和。
这个问题相当于对每个导出子图的每个点黑白染色,要求连通的点必须同色的方案数之和。
那么记 \(f[i][s]\) 表示目前做到第 \(i\) 个点,\(s\) 是一个 \(12\) 位的 \(3\) 进制数,表示 \(i-11\sim i\) 这 \(12\) 个点的状态(不在导出子图中,染成白色,染成黑色)。转移直接枚举 \(f[i-1][s]\) 和 \(i\) 的状态即可。
最后答案如果是 \(2\), 输出 \(1\),否则输出 \(0\)。
时间复杂度 \(O(3^{12}n)\)。
有个神仙用连通性 \(\text{dp}\) + 神仙剪枝,过了。
Code
#include <bits/stdc++.h>
using namespace std;
template <class t>
inline void read(t & res)
{
char ch;
while (ch = getchar(), !isdigit(ch));
res = ch ^ 48;
while (ch = getchar(), isdigit(ch))
res = res * 10 + (ch ^ 48);
}
const int o = 531446;
int p[55], f[55][o], n, m, ans;
bool bo[55][55];
inline void add(int &x, int y)
{
x += y; x &= 3;
}
inline int calc(int x, int y)
{
return x / p[y] % 3;
}
int main()
{
freopen("graph.in", "r", stdin);
freopen("graph.out", "w", stdout);
read(n); read(m);
int i, s, x, y, j;
while (m--)
{
read(x); read(y);
bo[x][y] = bo[y][x] = 1;
}
p[0] = 1;
for (i = 1; i <= 12; i++) p[i] = p[i - 1] * 3;
f[1][0] = f[1][p[11]] = f[1][2 * p[11]] = 1;
for (i = 2; i <= n; i++)
for (s = 0; s < p[12]; s++)
if (f[i - 1][s])
{
int v = f[i - 1][s], t = s / 3;
add(f[i][t], v);
bool pd1 = 1, pd2 = 1;
for (j = 0; j <= 11; j++)
if (i - 12 + j >= 1 && bo[i][i - 12 + j])
{
int x = calc(s, j);
if (x == 1) pd2 = 0;
else if (x == 2) pd1 = 0;
}
if (pd1) add(f[i][t + p[11]], v);
if (pd2) add(f[i][t + 2 * p[11]], v);
}
for (s = 0; s < p[12]; s++) add(ans, f[n][s]);
(ans += 3) &= 3;
if (ans == 2) ans = 1;
cout << ans << endl;
fclose(stdin);
fclose(stdout);
return 0;
}
T3
Description
定义两个字符串是相似的,当且仅当至多存在一个 \(i\) ,使得这两个字符串中只有第 \(i\) 个字母不同。
你取出了这个字符串中所有长度为 \(m\) 的子串。你想知道,对于每个长度为 \(m\) 的子串,有多少个其它长度为 \(m\) 的子串与它相似。
\(n,m\leq 10^5\),时空限制 \(3s/512MB\)。
Solution
记这个串为 \(S\), \(lcp(i,j)\) 表示 \(S[i\dots n]\) 和 \(S[j\dots n]\) 的最长公共前缀长度,\(lcs(i,j)\) 表示 \(S[1\dots i]\) 和 \(S[1\dots j]\) 的最长公共后缀长度。
问题转化为求有多少对 \(i,j\) 满足 \(lcp(i,j)+lcs(i+m-1,j+m-1)\geq m-1\)。
先对 \(S\) 的正串和反串都建 \(SAM\) 以及 \(parent\) 树。记 \(p1[i]\) 为第一棵 \(parent\) 树上 \(S[1\dots i+m-1]\) 对应点的编号,\(p2[i]\) 为第二棵 \(parent\) 树上 \(S[i\dots n]\) 对应点的编号。式子转化为 \(dep1[lca1(p1[i],p1[j])]+dep2[lca2(p2[i],p2[j])]\geq m-1\)。
接下来的这个实现方法可能过于麻烦,因为菜鸡看不懂标程只好自己瞎扯了。
考虑启发式合并,维护两棵树状数组 \(c,d\),下标是第二棵树的 \(dfs\) 序。
枚举 \(lca1(p1[i],p1[j])=x\),先考虑轻子树(包括点 \(x\))之间的贡献:我们先正序枚举轻儿子 \(v\)(包括点 \(x\)),然后把子树 \(v\) \(\text{dfs}\) 一遍。设 \(\text{dfs}\) 到节点 \(u\),如果 \(u\) 对应 \(S[1\dots i+m-1]\)。记 \(y\) 为 \(p2[i]\) 到根的路径上,满足 \(dep2[y]>=m-1-dep1[x]\) 的最深节点(用倍增找)。然后在 \(c\) 上求出有多少个点在 \(y\) 子树中,就是对 \(ans[i]\) 的贡献。
然后再把 \(v\) 子树 \(\text{dfs}\) 一遍。在 \(c\) 上把 \(dfn2[u]\) 这个位置的值 \(+1\)。
然后把轻子树都 \(\text{dfs}\) 一遍,清空 \(c\) 数组。然后倒序枚举轻儿子,再执行一遍上述过程,就把轻子树(包括点 \(x\))之间的贡献全部计算好了。
考虑重子树对轻子树的贡献,维护 \(d\) 数组,位置 \(i\) 表示重子树中有几个 \(dfn2=i\) 的点。把所有轻子树的点遍历一遍,在 \(d\) 数组上区间查,即可得到重子树对其贡献。
考虑轻子树对重子树的贡献。显然不可以把重子树 \(\text{dfs}\) 一遍。记 \(x\) 的重儿子为 \(son_x\)。枚举所有轻子树中的点 \(u\),显然会对满足 \(dfn1∈[dfn1[son_x],dfn1[son_x]+sze1[son_x]-1],dfn2∈[dfn2[y],dfn2[y]+sze2[y]-1]\) 的点产生 \(1\) 的贡献。这一部分的贡献相当于矩形加,单点查,离线 \(+\) 扫描线解决即可。
这到底要遍历多少次轻子树啊。
时间复杂度 \(O(n\log ^2n)\)。常数大的一批,但是 \(3s\) 还是稳的。
Code
#include <bits/stdc++.h>
using namespace std;
template <class t>
inline void print(t x)
{
if (x > 9) print(x / 10);
putchar(x % 10 + 48);
}
const int e = 2e5 + 15;
struct line
{
int l, r, v;
line(){}
line(int _l, int _r, int _v) :
l(_l), r(_r), v(_v) {}
};
int c[e], d[e], son[e], n, m, ans[e], p1[e], p2[e], L, f[e][18], szeA[e], szeB[e], rt;
int lst_y[e], dfn_l, dfn_r, dfnA[e], dfnB[e], timA, timB, real_ans[e];
char s[e];
vector<line>g[e];
vector<int>h[e];
struct SAM
{
struct point
{
int go[26];
}t[e];
int maxl[e], fa[e], tot = 1, lst = 1, id[e], anc[e][18], dep[e];
vector<int>g[e];
inline void insert(char s)
{
int c = s - 'a', i = lst;
lst = ++tot;
maxl[lst] = maxl[i] + 1;
for (; i && !t[i].go[c]; i = fa[i]) t[i].go[c] = lst;
if (!i) fa[lst] = 1;
else
{
int j = t[i].go[c];
if (maxl[j] == maxl[i] + 1) fa[lst] = j;
else
{
int p;
t[p = ++tot] = t[j];
fa[p] = fa[j];
fa[j] = fa[lst] = p;
maxl[p] = maxl[i] + 1;
for (; i && t[i].go[c] == j; i = fa[i]) t[i].go[c] = p;
}
}
}
inline void build()
{
for (int i = 2; i <= tot; i++) g[fa[i]].push_back(i);
}
}A, B;
inline void change(int *c, int x, int v)
{
for (int i = x; i <= L; i += i & -i) c[i] += v;
}
inline int query(int *c, int x)
{
int res = 0;
for (int i = x; i; i -= i & -i) res += c[i];
return res;
}
inline void dfsA(int u)
{
dfnA[u] = ++timA;
szeA[u] = 1;
int len = A.g[u].size(), i;
for (i = 0; i < len; i++)
{
int v = A.g[u][i];
dfsA(v);
szeA[u] += szeA[v];
if (szeA[v] > szeA[son[u]]) son[u] = v;
}
}
inline void dfsB(int u)
{
dfnB[u] = ++timB;
szeB[u] = 1;
int len = B.g[u].size(), i;
for (i = 0; i < 17; i++) f[u][i + 1] = f[f[u][i]][i];
for (i = 0; i < len; i++)
{
int v = B.g[u][i];
f[v][0] = u;
dfsB(v);
szeB[u] += szeB[v];
}
}
inline int jumpB(int x, int d)
{
for (int i = 17; i >= 0; i--)
if (f[x][i] && B.maxl[f[x][i]] >= d) x = f[x][i];
return x;
}
inline void add(int u)
{
if (!A.id[u]) return;
int pos = A.id[u], z = p2[pos];
change(c, dfnB[z], 1);
}
inline void del(int u)
{
if (!A.id[u]) return;
int pos = A.id[u], z = p2[pos];
change(c, dfnB[z], -1);
}
inline void ask(int u, int x)
{
if (!A.id[u]) return;
int pos = A.id[u], z = p2[pos], y = jumpB(z, m - 1 - A.maxl[x]);
lst_y[u] = y;
ans[pos] += query(c, dfnB[y] + szeB[y] - 1) - query(c, dfnB[y] - 1);
}
inline void calc_son(int u)
{
if (!A.id[u]) return;
int pos = A.id[u], z = p2[pos], y = lst_y[u];
ans[pos] += query(d, dfnB[y] + szeB[y] - 1) - query(d, dfnB[y] - 1);
}
inline void ins(int u)
{
if (!A.id[u]) return;
int pos = A.id[u], z = p2[pos];
change(d, dfnB[z], 1);
}
inline void clear(int u)
{
if (!A.id[u]) return;
int pos = A.id[u], z = p2[pos];
change(d, dfnB[z], -1);
}
inline void join(int u)
{
if (!A.id[u]) return;
int y = lst_y[u];
g[dfn_l].push_back(line(dfnB[y], dfnB[y] + szeB[y] - 1, 1));
g[dfn_r + 1].push_back(line(dfnB[y], dfnB[y] + szeB[y] - 1, -1));
}
inline void dfs_add(int u)
{
add(u);
int len = A.g[u].size(), i;
for (i = 0; i < len; i++) dfs_add(A.g[u][i]);
}
inline void dfs_del(int u)
{
del(u);
int len = A.g[u].size(), i;
for (i = 0; i < len; i++) dfs_del(A.g[u][i]);
}
inline void dfs_ask(int u, int x)
{
ask(u, x);
int len = A.g[u].size(), i;
for (i = 0; i < len; i++) dfs_ask(A.g[u][i], x);
}
inline void dfs_cs(int u)
{
calc_son(u);
int len = A.g[u].size(), i;
for (i = 0; i < len; i++) dfs_cs(A.g[u][i]);
}
inline void dfs_ins(int u)
{
ins(u);
int len = A.g[u].size(), i;
for (i = 0; i < len; i++) dfs_ins(A.g[u][i]);
}
inline void dfs_clear(int u)
{
clear(u);
int len = A.g[u].size(), i;
for (i = 0; i < len; i++) dfs_clear(A.g[u][i]);
}
inline void dfs_join(int u)
{
join(u);
int len = A.g[u].size(), i;
for (i = 0; i < len; i++) dfs_join(A.g[u][i]);
}
inline void dfsC(int u, bool op)
{
int i, len = A.g[u].size();
for (i = 0; i < len; i++)
{
int v = A.g[u][i];
if (v != son[u]) dfsC(v, 0);
}
if (son[u]) dfsC(son[u], 1);
ask(u, u); add(u);
for (i = 0; i < len; i++)
{
int v = A.g[u][i];
if (v != son[u])
{
dfs_ask(v, u);
dfs_add(v);
}
}
del(u);
for (i = 0; i < len; i++)
{
int v = A.g[u][i];
if (v != son[u]) dfs_del(v);
}
for (i = len - 1; i >= 0; i--)
{
int v = A.g[u][i];
if (v != son[u])
{
dfs_ask(v, u);
dfs_add(v);
}
}
ask(u, u);
for (i = 0; i < len; i++)
{
int v = A.g[u][i];
if (v != son[u]) dfs_del(v);
}
calc_son(u);
for (i = 0; i < len; i++)
{
int v = A.g[u][i];
if (v != son[u]) dfs_cs(v);
}
if (op)
{
ins(u);
for (i = 0; i < len; i++)
{
int v = A.g[u][i];
if (v != son[u]) dfs_ins(v);
}
}
else if (son[u]) dfs_clear(son[u]);
if (son[u])
{
dfn_l = dfnA[son[u]];
dfn_r = dfn_l + szeA[son[u]] - 1;
join(u);
for (i = 0; i < len; i++)
{
int v = A.g[u][i];
if (v != son[u]) dfs_join(v);
}
}
}
int main()
{
freopen("string.in", "r", stdin);
freopen("string.out", "w", stdout);
cin >> n >> m;
int i, j;
scanf("%s", s + 1);
for (i = 1; i <= n; i++)
{
A.insert(s[i]);
if (i >= m) A.id[A.lst] = i - m + 1, p1[i - m + 1] = A.lst;
}
for (i = n; i >= 1; i--)
{
B.insert(s[i]);
if (i + m - 1 <= n) B.id[B.lst] = i, p2[i] = B.lst;
}
A.build(); B.build(); L = B.tot;
dfsA(1); dfsB(1); dfsC(1, 0);
memset(c, 0, sizeof(c));
for (i = 1; i <= n - m + 1; i++) h[dfnA[p1[i]]].push_back(i);
for (i = 1; i <= A.tot; i++)
{
int leng = g[i].size();
for (j = 0; j < leng; j++)
{
line tmp = g[i][j];
change(c, tmp.l, tmp.v);
change(c, tmp.r + 1, -tmp.v);
}
int lenh = h[i].size();
for (j = 0; j < lenh; j++)
{
int x = h[i][j];
ans[x] += query(c, dfnB[p2[x]]);
}
}
for (i = 1; i <= n - m + 1; i++)
{
print(ans[i]);
if (i == n - m + 1) putchar('\n');
else putchar(' ');
}
fclose(stdin);
fclose(stdout);
return 0;
}