A.Nastia and Nearly Good Numbers
很明显 b = 1 b = 1 b=1 时无解,此外 a + a ∗ b = a ∗ ( b + 1 ) a + a * b = a * (b + 1) a+a∗b=a∗(b+1) 肯定是一组解。
AC代码:
#include <bits/stdc++.h>
using namespace std;
signed main()
{
cin.tie(nullptr);
ios_base::sync_with_stdio(false);
int t;
cin >> t;
while(t --)
{
long long A, B;
cin >> A >> B;
if(B == 1)
{
cout << "NO" << '\n';
}
else
{
cout << "YES" << '\n';
cout << A << ' ' << A * B << ' ' << A * (B + 1) << '\n';
}
}
}
B. Nastia and a Good Array
找到最小值,以最小值位置左右递增 1 1 1,结论大概是没有两个相邻的数 g c d gcd gcd 是大于 1 1 1 的。
AC代码:
#include <bits/stdc++.h>
using namespace std;
signed main()
{
cin.tie(nullptr);
ios_base::sync_with_stdio(false);
int t;
cin >> t;
while(t --)
{
int n;
cin >> n;
vector <int> a(n + 5);
int min_val = 1e9 + 5;
int pos = 0;
for(int i = 1; i <= n; ++i)
{
cin >> a[i];
if(min_val > a[i])
{
min_val = a[i];
pos = i;
}
}
cout << n - 1 << '\n';
for(int i = 1; i <= n; ++i)
{
if(pos == i)
continue;
cout << pos << ' ' << i << ' ' << min_val << ' ' << min_val + abs(i - pos) <<'\n';
}
}
}
C. Nastia and a Hidden Permutation
很有意思的一道题目,先观察两个式子:
{ t = 1 , m a x ( m i n ( x , p i ) , m i n x ( x + 1 , p j ) ) t = 2 , m i n ( m a x ( x , p i ) , m a x ( x + 1 , p j ) ) \begin{cases}t = 1, \,max(min(x, \,p_i),\,minx(x + 1,\,p_j))\\t = 2, \,min(max(x, \,p_i),\,max(x + 1,\,p_j))\end{cases} {t=1,max(min(x,pi),minx(x+1,pj))t=2,min(max(x,pi),max(x+1,pj))
将 1 1 1 带入两个式子, 我们分别可以化简得:
1
:
m
a
x
(
1
,
m
i
n
(
2
,
p
j
)
)
1:max(1,\,min(2,\,p_j))
1:max(1,min(2,pj))
2
:
m
i
n
(
p
i
,
m
a
x
(
2
,
p
j
)
)
2 :min(p_i,\,max(2,\,p_j))
2:min(pi,max(2,pj))
考虑枚举 i i i 和 i + 1 i + 1 i+1 位置,利用式子 2 2 2,当出 1 1 1 或者 2 2 2 时,我们可以分别再用 0 0 0 和 1 1 1 次, 得到 1 1 1 的位置,带入式子 1 1 1 ,可以得到:
m a x ( 1 , m i n ( x + 1 , p j ) ) \quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad\quad max(1,\,min(x +1,\,p_j)) max(1,min(x+1,pj))
当 x = n − 1 x=n-1 x=n−1 时,我们可以得到所有的值。
AC代码:
#include <bits/stdc++.h>
using namespace std;
signed main()
{
int t;
cin >> t;
while(t --)
{
int n;
cin >> n;
int mark = 0;
for(int i = 1; i < n; i += 2)
{
cout << "? 2 " << i << ' ' << i + 1 << ' ' << 1 << '\n';
int x;
cin >> x;
if(x == 1)
{
mark = i;
break;
}
else if(x == 2)
{
cout << "? 2 " << i + 1 << ' ' << 1 << ' ' << 1 << '\n';
cin >> x;
if(x == 1)
{
mark = i + 1;
break;
}
}
}
vector <int> a(n + 5);
if(!mark)
mark = n;
a[mark] = 1;
for(int i = 1; i <= n; ++i)
{
if(mark != i)
{
cout << "? 1 " << mark << ' ' << i << ' ' << n - 1 << '\n';
cin >> a[i];
}
}
cout << "!";
for(int i = 1; i <= n; ++i)
{
cout << ' ' << a[i];
}
cout << '\n';
}
}
D. Nastia Plays with a Tree
思路应该其实很简单,一个父节点当有两个或者两个以上的子节点时,就要考虑拆分和拼接。
1
:
1:
1:两个子节点,跟父节点断开,再把一个子节点连回去。
2
:
2:
2:两个以上的子节点,我们考虑先断开,再把子节点连上去,直到来到情况
1
1
1。
AC代码:
#include <bits/stdc++.h>
using namespace std;
int root;
signed main()
{
cin.tie(nullptr);
ios_base::sync_with_stdio(false);
int t;
cin >> t;
while(t --)
{
int n;
cin >> n;
vector <int> e[n + 5];
unordered_map <int, int> d;
for(int i = 1; i < n; ++i)
{
int u, v;
cin >> u >> v;
e[u].emplace_back(v);
e[v].emplace_back(u);
++ d[u], ++d[v];
}
for(auto x : d)
{
if(x.second == 1)
root = x.first;
}
vector <array <int, 4>> ans;
function <int(int, int)> DFS = [&](int u, int fa)
{
int son_num = 0, lst = u;
for(auto v : e[u])
{
if(v == fa)
continue;
int nxt = DFS(v, u);
if(!(~nxt))
continue;
++ son_num;
if(son_num == 1)
{
lst = nxt;
}
else if(son_num == 2)
{
array <int, 4> a;
a = {u, fa, nxt, root};
root = lst;
ans.emplace_back(a);
lst = -1;
}
else
{
array <int, 4> a;
a = {u, v, nxt, root};
root = v;
ans.emplace_back(a);
}
}
return lst;
};
DFS(root, 0);
cout << (int) ans.size() << '\n';
for(auto x : ans)
{
cout << x[0] << ' ' << x[1] << ' ' << x[2] << ' ' << x[3] << '\n';
}
}
}