以0和1的形式查找倍数

时间:2013-08-15 15:22:50

标签: algorithm number-theory

我试图解决http://poj.org/problem?id=1426(2002年达卡地区)。虽然我无法提出所需的确切算法,但是当n从1变化到200时,我通过生成二进制数并检查可分性来预先计算所有值。现在我有一个恒定的时间算法:)但我相信这不是解决问题的正确方法。我不想使用图搜索算法,因为这个问题是在一个站点的基本数学下进行的,所以我认为必须有一个数学解决方案来解决这个问题而不给TLE。

1 个答案:

答案 0 :(得分:2)

这是剩下的一个简单伎俩。

必须只用0和1来写每个倍数,意味着你想要一个10的一些幂之和的倍数,这意味着某些{a(i)的x = \ sum {10 ^ a(i)} }。要找到我们想要保留的正确索引,您必须记住,作为数字n的倍数意味着x mon n = 0。

所以,所有关于写入10 mod n的幂,并找到一个和为0 mod n的子集。 让我们试试19:

Num -> Num mod 19
1 -> 1
10 -> 10
10^2 -> 5
10^3 -> 12
10^4 -> 6
10^5 -> 3

现在,我们可以看到10 ^ 1 + 10 ^ 4 + 10 ^ 5 = 19即0 mod 19,所以我们的解决方案是110010。 要找到提醒模型19,您不必计算每一个功率,您只需将前一个值mod 19乘以10,然后计算模块。

例如,10 ^ 4 mod 10 = 10 ^ 3 * 10 mod 19 = 12 * 10 mod 19 = 6,这比计算10 ^ 4更容易(也许它不适用于小功率,但想象一下必须计算在制作它之前100 ^ 100 19)。

修改

剩下的唯一问题是找到一个总和为0 mod n的子集,假设存在这样的子集。

修改

好的,我有一个想法,可以达到n = 200并解决线性时间问题。基本上,你利用了sumn modn迟早会重叠的事实。这是真的,因为hte pigeot原则,但在特定情况下,只有100个整数,让它工作只是一个单纯的情况。无论如何,给定如前所示计算的提醒列表,您开始计算部分总和。如果你遇到了你已经拥有的价值,你就有了解决方案(i-1 1后跟j 0)。如果你遇到提醒0,你也做得很好。

这是我编写的C#代码来测试它:

for (int n = 2; n <= 200; n++)
{
    int[] reminder = new int[100];
    reminder[0] = 1;
    for (int i = 1; i < 100; i++)
    {
        reminder[i] = (10 * reminder[i - 1]) % n; 
    }
    var lst = reminder.Select((x, y) => new TenPower { Reminder = x, Pow = y })
        .ToList();

    bool cont = true;
    for (int i = 1; (i < 100)&&cont; i++)
    {
        if (lst[i].Reminder == 0)
        {
            cont = false;
            Console.WriteLine(n +" :: " + Math.Pow(10, lst[i].Pow));
        }
        else
        {
            lst[i].Reminder = (lst[i].Reminder + lst[i - 1].Reminder) % n;
            if (lst[i].Reminder == 0)
            {
                cont = false;
                Console.WriteLine(n + " :: " + Math.Pow(10, lst[i].Pow));
            }
            for (int j = i - 1; (j > 0) && cont; j--)
            {
                if (lst[i].Reminder == lst[j].Reminder)
                {
                    cont = false;
                    Console.Write(n + " :: ");
                    for (int k = 0; k < i - j; k++)
                    {
                        Console.Write("1");
                    }
                    for (int k = i - j-1; k < i; k++)
                    {
                        Console.Write("0");
                    }
                    Console.WriteLine();
                }
            }
        }
    }
}