Skip to content

题解-CF1744D

Posted on:2023年8月12日 at 19:15

本文章遵守知识共享协议 CC-BY-NC-SA,同步发表于洛谷题解区,转载时须在文章的任一位置附上原文链接和作者署名(rickyxrc)。推荐在我的个人博客阅读。

把我卡了好久……

题面大意

给定整数序列 SS ,你可以选出一个操作集 QQ,满足 qQ,q[1,n]\forall q \in Q,q \in [1,n],然后将所有 SqS_q 替换成 qSqqS_q,求要使原序列能被 2n2^n 整除所需的最少操作次数。

解题思路

只记录每个数 22 的因子的出现次数即可。

同时,为了确保操作次数最少,我们肯定首选 22 的次幂最多的数字进行乘法。

所以我们可以设计一个简单的 dp,定义 fif_iii 含有 22 的因子的个数,我们不难得到 fi={fi2+1(i=2k,kN)0f_i = \begin{cases}f_\frac{i}{2}+1 & (i = 2k,k \in N) \\ 0\end{cases}

最后将 ff 数组排序,从大往小减即可。

#include <stdio.h>
#include <algorithm>
#include <string.h>

typedef long long i64;
const i64 mod = 1, maxn = 200007;

i64 T, n, li[maxn], lg[maxn], res, p2, t2, solved, logg[maxn], op, rem;

int main()
{
    scanf("%lld", &T);

    while (T--)
    {
        scanf("%lld", &n);
        rem = n;
        op = 0;

        memset(logg, 0, sizeof logg);
        logg[2] = 1;
        for (int i = 3; i <= n; i++)
            if (!(i & 1))
                logg[i] = logg[i >> 1] + 1;
            else
                logg[i] = 0;

        for (int i = 0; i < n; i++)
            scanf("%lld", li + i);

        for (int i = 0; i < n; i++)
            while (!(li[i] & 1))
                li[i] >>= 1,
                    rem--;

        if (rem <= 0)
            printf("0\n");
        else
        {
            std::sort(logg, logg + n + 1);
            for (int i = n; i; i--)
            {
                rem -= logg[i];
                op++;
                if (rem <= 0)
                {
                    printf("%d\n", op);
                    break;
                }
            }

            if (rem > 0)
                printf("-1\n");
        }
    }
    return 0;
}


在 Rickyxrc's blog 出现的文章,若无特殊注明,均采用 CC BY-NC-SA 4.0 协议共享,也就是转载时需要注明本文章的地址,并且引用本文章的文章也要使用相同的方式共享。