CF 1521题解

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+ab=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)) 1max(1,min(2,pj))
2 : m i n ( p i ,   m a x ( 2 ,   p j ) ) 2 :min(p_i,\,max(2,\,p_j)) 2min(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=n1 时,我们可以得到所有的值。

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';
        }
    }
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值