Namomo Test Round 1 题解

倾情打造的Namomo上线啦

A

(b − 1) * a ≥ n − 1 输出 Yes,

假设最小的数排在最末尾,则每次排序上升(冒泡) b - 1 个数字

最底最小数都冒泡到了最顶部, 那其他数早就冒泡好了

#include <bits/stdc++.h>
#define all(n) (n).begin(), (n).end()
#define se second
#define fi first
#define pb push_back
#define mp make_pair
#define sqr(n) (n)*(n)
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define per(i,a,b) for(int i=a;i>=(b);--i)
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
typedef vector<int> VI;
typedef double db;

const int N = 1e5 + 5;

ll n, m, _, k;

int main() 
{
    ios::sync_with_stdio(0); cin.tie(0);
    for (cin >> _; _; --_) 
    {
        ll a, b; cin >> n >> a >> b;
        if (n - 1 <= (b - 1) * a) cout << "Yes
";
        else cout << "No
";
    }
    return 0;
}

B

不开ll见祖宗

对于每次不知情, 帽子 i 被选择的概率为 x = (n - 2) / n, 被选择的概率为 y = 1 - (n - 2) / n = 2 / n

假设当前帽子 i 有的概率为 a, 则此次不知情的操作后 概率为 a * x + y * (1 - a) / n

我们变换一下 y = y / n, z = x - y, 则

a * x + y * (1 - a) / n = a * z + y

那多次不知情操作呢?

(((a * z + y) * z + y) * z + y) ... = a * z ^ k + y * z ^ (k - 1) + y * z ^ (k - 2) + ... + y * z ^ 0

发现没有, 我们可以预处理 z的n次方 和 y * z ^ k 的前缀和, 那么多次操作就是 O(1)

然后我们还发现, 只有一只帽子的概率最大(最开始这个帽子编号为 1), 其他帽子概率相等,

所以我们对于知情操作, 纪录哪个帽子概率最大即可, 那我们就只用保存两个答案即可

#include <bits/stdc++.h>
#define all(n) (n).begin(), (n).end()
#define se second
#define fi first
#define pb push_back
#define mp make_pair
#define sqr(n) (n)*(n)
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define per(i,a,b) for(int i=a;i>=(b);--i)
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
typedef vector<int> VI;
typedef double db;

const int N = 100005;
const int mod = 998244353;

int n, m, _, k, now;
ll ans[2], s[N], g[N], x, y, z;

ll quick(ll k1, ll k2)
{
    ll k3 = 1;
    for (; k2; k2 >>= 1, k1 = k1 * k1 % mod)
        if (k2 & 1) k3 = 1ll * k3 * k1 % mod;
    return k3;
}

ll get(ll a, ll b)
{
    return a * quick(b, mod - 2) % mod;
}

void work(int c)
{
    if (c == 0) return;
    rep(i, 0, 1) ans[i] =  (ans[i] * g[c] % mod + s[c - 1]) % mod;
}

void init()
{
    ans[1] = 0;
    now = ans[0] = g[0] = 1;

    x = get(n - 2, n), y = get(2, (ll)n * (n - 1) % mod), z = (x - y + mod) % mod;

    s[0] = y; 
    rep(i, 1, m) g[i] = g[i - 1] * z % mod, s[i] = (s[i - 1] + g[i] * y % mod) % mod;
}

int main()
{
    ios::sync_with_stdio(0); cin.tie(0);
    for (cin >> _; _; --_)
    {
        cin >> n >> m >> k; now = 1;

        if (n == 2) { cout << (m % 2 == 0 ? "1 0
" : "0 1
"); continue; }

        init(); work(m - k);

        rep(i, 1, k)
        {
            int a, b, c; cin >> a >> b >> c;

            if (c == now) now = b;
            else if (b == now) now = c;
        }

        rep(i, 1, n) cout << (now == i ? ans[0] : ans[1]) << ' ';
        cout << endl;
    }
    return 0;
}

C

直接丢官方题解思路

给出一个矩阵快速幂的做法。

首先当 x=k 时,满足 y-l≡2或4(mod6)时答案为1,否则答案为0。下面讨论 x<k:

小沃沃路线分为:

从标号为 x 的正六边形的 y 号点出发,走到标号为 x 的正六边形的 1/2 号点。

从标号为 x 的正六边形的 1/2 号点出发,走到从标号为 x+1 的正六边形的 1/2 号点。

...

从标号为 k-2 的正六边形的 1/2 号点出发,走到从标号为 k-1 的正六边形的 1/2 号点。

从标号为 k−1 的正六边形的 1/2 号点出发,走到从标号为 k 的正六边形的 l 号点。

设一个正六边形中小沃沃的四种状态:位于 1 号点方向为右上方、位于 1 号点方向为右方、位于 2 号点方向为右上方、位于 2 号点方向为右方。 对应代码顺序为 : 1, 0, 3, 2

手推出从一个正六边形的四种状态走到下一个正六边形的四种状态所需要花费的最少体力,得到一个 4∗4 的转移矩阵 A,矩阵快速幂求出 (A^{k-x-1})

,其中矩阵乘法中的乘法运算和加法运算分别替换为加法运算和取min运算。于是 (A^{k-x-1})

的元素分别表示从标号为 x 的正六边形的四种状态走到标号为 k-1 的正六边形的四种状态所需要花费的最少体力。

之后手推出从标号为 x 的正六边形的 y 号点出发得到四种状态所需花费的最少体力,以及从标号为 k-1 的正六边形的四种状态出发得到标号为 k 的正六边形的 l 号点所需花费的最少体力。分别枚举四种状态更新答案即可。

#include <bits/stdc++.h>
#define all(n) (n).begin(), (n).end()
#define se second
#define fi first
#define pb push_back
#define mp make_pair
#define sqr(n) (n)*(n)
#define rep(i,a,b) for(int i=a;i<=(b);++i)
#define per(i,a,b) for(int i=a;i>=(b);--i)
using namespace std;
typedef long long ll;
typedef pair<int, int> PII;
typedef vector<int> VI;
typedef double db;

const int N = 100005;

struct matrix
{
    ll a[4][4];

    matrix() 
    { 
        rep (i, 0, 3) 
            rep (j, 0, 3)
                a[i][j] = 2e18;
    }

    matrix operator * (matrix &B)
    {
        matrix C;
        rep (i, 0, 3)
            rep (j, 0, 3)
                rep (k, 0, 3)
                    C.a[i][j] = min(C.a[i][j], a[i][k] + B.a[k][j]);
        return C;
    }

    matrix operator ^ (ll k)
    {
        matrix res, A = (*this);
        rep (i, 0, 4) res.a[i][i] = 0;

        for (; k; k >>= 1, A = A * A) 
            if(k & 1) res = res * A;

        return res;
    }
}A;

int n, m, _;
ll a, b;

ll trans[4][4] = 
{
    {2,1,2,1},
    {1,2,1,0},
    {0,1,2,1},
    {1,2,1,2}
};

ll S[6][4] = 
{
    {0,0,1,1},
    {1,1,0,0},
    {1,1,0,1},
    {0,1,1,1},
    {1,1,1,0},
    {1,0,1,1}
};

ll T[4][6] = 
{
    {1,1,1,1,0,0},
    {1,0,1,1,0,1},
    {0,1,1,0,1,1},
    {1,1,0,0,1,1}
};

int main()
{
    ios::sync_with_stdio(0); cin.tie(0);

    memcpy(A.a,trans, sizeof(trans));

    for (cin >> _; _; --_)
    {
        cin >> a >> n >> b >> m;
        if (a > b) swap(a, b), swap(n, m);

        if(a == b)
        {
            int x = (n - m + 6) % 6;
            if(x == 2 || x == 4) cout << 1 << '
';
            else cout << 0 << '
';
        }
        else if(a + 1 == b && (n == 1 || n == 2) && (m == 4 || m == 5)) cout << 0 << '
';
        else
        {
            matrix B = A ^ (b - a - 1);
            ll ans = 2e18;
            rep (i, 0, 3) 
                rep (j, 0, 3)
                    ans = min(ans, S[n - 1][i] + B.a[i][j] + T[j][m - 1]);
            
            cout << ans << '
';
        }
    }
    return 0;
}
原文地址:https://www.cnblogs.com/2aptx4869/p/13134486.html