牛客周赛141

A 回文(version 1)

知识点:判断回文字符串

思路:判断是否为完全平方数,再判断这个数和他的平方根是否为回文即可

注意:不要读错题,不是这个数和他的平方,而是这个数和他的平方根

未知(version 1)

知识点:异或性质

思路:一个数异或他自己为 \(0\),所以异或 \(y\) 就可以了

回文(version 2)

知识点:模拟,

思路:把 \(nn\) 全换成 \(m\) 就行了

未知(version 2)

知识点:枚举

思路:如果有两个甚至多个 \(1\),或者有一个 \(1\) 和两个相同的数,就已经满足条件了。如果没有这些条件,注意到,\(a_i\) 的最大值也才 \(1e9\),就是底数是 \(2\),指数也最高到达 \(30\) ,所以 \(a_j\) 的范围为 \(2-30\) ,而且相同的数再次遍历是没有意义的,所以直接遍历一次就可以,时间复杂度很小,先对原数组进行排序,这样如果超出范围了直接 \(break\) 就行了。

点击查看代码
void solve()
{
    cin >> n;
    vi a(n);
    int c1 = 0;
    bool ok = 0;

    for (int i = 0; i < n; i++)
    {
        cin >> a[i];
        if (a[i] == 1)
            c1++;
    }
    sort(all(a));
    for (int i = 1; i < n; i++)
    {
        if (a[i] == a[i - 1] && a[i] != 1)
            ok = 1;
    }
    if (c1 >= 2 || (c1 == 1 && ok))
    {
        cout << "YES" << endl;
        return;
    }
    for (int i = 0; i < n; i++)
    {
        if (a[i] == 1 || (i > 0 && a[i] == a[i - 1]))
            continue;

        for (int j = 0; j < n; j++)
        {
            if (a[j] == 1 || (j > 0 && a[j] == a[j - 1]))
                continue;
            if (a[j] >= 30)
                break;
            int num = 1;
            for (int k = 0; k < a[j]; k++)
            {
                num *= a[i];
            }
            if (num > 1000000000LL)
                break;
            if (binary_search(a.begin(), a.end(), num))
            {
                cout << "YES" << endl;
                return;
            }
        }
    }

    cout << "NO" << endl;
}

未知(version 3)

知识点:构造

思路:先考虑构造成功的必要条件,对于 \(m\) 级来说,至少需要 \(m+1\) 个点来构造,剩下的 \(m-1\) 级,至少需要一个点来构造,最多需要 \(i\) 个点来构造, 所以 \(n>2*m\),且 \(n<m*(m+1)/2+1\),如果点的数量合法,那我们开始构造。

先构造出主链,对于下一个层级,计算这个层级最多容纳的点的数量 ,应该是 \(min(i,剩下的所有可支配点)\),找出这条链在主链上的起点进行连接即可

Code
点击查看代码
void solve()
{
    cin >> n >> m;
    int ceng = m;
    int idx = 2;
    if (n < 2 * m || n > 1 + m * (m + 1) / 2)
    {
        cout << "NO" << endl;
        return;
    }
    cout << "YES" << endl;
    for (int i = 1; i <= m; i++)
    {
        cout << i << ' ' << idx << endl;
        idx++;
    }
    ceng--;
    while (ceng >= 1)
    {
        int res = n - idx + 1;
        int mx = res - ceng;

        int t = min(mx, ceng - 1);
        int cnt = 1 + t;
        int chu = (ceng - cnt) + 1;

        int pre = chu;
        while (cnt--)
        {
            cout << pre << ' ' << idx << endl;
            pre = idx;
            idx++;
        }
        ceng--;
    }
}

回文(version 3)

知识点:前缀和,二次前缀和

思路:如果 \(x=1\),结果为区间长度,如果 \(x=2\),结果为区间内每个字符里面选两个即可,这两种情况比较好处理 ,考虑当 \(x=3\) 的时候,先考虑暴力做法,中间那个字符是不需要考虑的,所以遍历字符串,处理每一个字符,利用乘法原理将两边字符的数量相乘即可,数量由前缀和就可以得出,但这样的时间复杂度太高,所以对计算的数学式子进行化简,遍历字符串,当遍历到第 \(i\) 个字符时,对于左右两边每个字符来说,有贡献 \((p_{i-1}-p_{l-1})*(p_r-p_i)\),拆解得到,\((p_{i-1}*p_r)+(p_{l-r}*p_i)+(-p_{l-1}*p_r)+(-p_i*p_{i-1})\) 共四项,对于第四项,可以预处理然后用前缀和计算,对于第三项,可以直接用前缀和得到,对于前两项,发现均有一项是固定的,变得是 \(i\),所以预处理他们的和然后相乘即可,他们的和是在对原前缀和的基础上进行二次前缀和。

Code
点击查看代码
int f[M][26];
int s1[M][26];
int a[M][26];
int s3[M][26];
void solve()
{
    int q;
    cin >> n >> q;
    cin >> s;
    s = '3' + s;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 0; j < 26; j++)
        {
            f[i][j] = f[i - 1][j];
        }
        f[i][s[i] - 'a']++;
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 0; j < 26; j++)
        {
            s1[i][j] = s1[i - 1][j];
            s1[i][j] += f[i][j];
        }
    }
    for (int i = 1; i <= n; i++)
    {
        for (int j = 0; j < 26; j++)
        {
            s3[i][j] = s3[i - 1][j];
            a[i][j] = -f[i - 1][j] * f[i][j];
            s3[i][j] += a[i][j];
        }
    }

    while (q--)
    {
        cin >> l >> r >> x;
        if (x == 1)
        {
            cout << r - l + 1 << endl;
        }
        else if (x == 2)
        {
            int res = 0;
            for (int i = 0; i < 26; i++)
            {
                int sum = f[r][i] - f[l - 1][i];
                res += sum * (sum - 1) / 2;
            }
            cout << res << endl;
        }
        else
        {
            int res = 0;
            for (int i = 0; i < 26; i++)
            {
                res += s3[r][i] - s3[l - 1][i];
                res += (r - l + 1) * (-f[l - 1][i] * f[r][i]);
                int d = (l >= 2) ? s1[l - 2][i] : 0;
                res += f[r][i] * (s1[r - 1][i] - d);

                res += f[l - 1][i] * (s1[r][i] - s1[l - 1][i]);
            }
            cout << res << endl;
        }
    }
}
posted @ 2026-04-27 16:44  Lambda_L  阅读(6)  评论(0)    收藏  举报