Project Euler 78:Coin partitions

Coin partitions

Let p(n) represent the number of different ways in which n coins can be separated into piles. For example, five coins can separated into piles in exactly seven different ways, so p(5)=7.

OOOOO
OOOO O
OOO OO
OOO O O
OO OO O
OO O O O
O O O O O

Find the least value of n for which p(n) is divisible by one million.


硬币分拆

记p(n)是将n枚硬币分拆成堆的不同方式数。例如,五枚硬币有7种分拆成堆的不同方式,因此p(5)=7。

OOOOO
OOOO O
OOO OO
OOO O O
OO OO O
OO O O O
O O O O O

找出使p(n)能被一百万整除的最小n值。

思路:

求数的拆分有多少种

再判断是否能被一百万整除

参考资料:wiki ,PartitionFunctionP

法一:

根据这个等式:

高能预警:

1.  这里是两部分的和

2.当第一个不满足条件,即:n<k(3k-1)/2 时候,第二个一定不成立

3.第一个满足条件,第二个可能不满足条件,这里说的条件都是数组下标不能越界

4.满足条件的都要计算,只有当第一个不满足条件的时候才本次循环

5.前面的(-1)^(k+1),要乘进去,展开计算,就是计算符合条件的数组

关键程序:

for(k=1;k<=n;k++){
                gk1 = k*(3*k-1)/2;
                gk2 = gk1+k;
                if(gk1>n) break;
                    plist.set(n,plist.get(n)+flag*plist.get(n-gk1));
                    if(gk2<=n){
                    plist.set(n,plist.get(n)+flag*plist.get(n-gk2));
                    }
                    plist.set(n,plist.get(n)%limit);
                    flag*=-1;
            }

这里由于我只是在上面看到的求解表达式,造成我搞了好久都没有搞出来,没文化正可怕

法二:

看到这里还没有出问题

看到这里,直接根据上面的表达式求解了,然而这里的k不是从1-n,这里我又理解错了,以为拿来用就好了

上面的方法不行,下面的方法也不行,真是浪费了好多时间的

下面程序中有一个求k的过程,这里才是真谛啊!!!

关键程序:

while(gk<=n){
                flag = (i%4>1)?-1:1;
                plist.set(n,plist.get(n)+flag*plist.get(n-gk));
                plist.set(n,plist.get(n)%limit);
                i++;
                int  k= (i%2==0)?i/2+1:-(i/2+1);
                gk = k*(3*k-1)/2;
            }

Java程序:

package Level3;

import java.util.ArrayList;

public class PE078{

    void run(){
        int limit = 1000000;
        partitions2(limit);
    }
    void partitions2(int limit){
        ArrayList<Integer> plist = new ArrayList<Integer>();
        plist.add(1);
        int n = 1;
        while(true){
            int gk1 =1;
            int gk2 =2;
            int k=1;
            plist.add(0);// 初始第n
            int flag = 1;
            for(k=1;k<=n;k++){
                gk1 = k*(3*k-1)/2;
                gk2 = gk1+k;
                if(gk1>n) break;
                    plist.set(n,plist.get(n)+flag*plist.get(n-gk1));
                    if(gk2<=n){
                    plist.set(n,plist.get(n)+flag*plist.get(n-gk2));
                    }
                    plist.set(n,plist.get(n)%limit);
                    flag*=-1;
            }
            if(plist.get(n)==0)
                break;
            n++;
        }
        System.out.println(n);
    }
//    55374
//    running time=0s784ms
    void partitions1(int limit){
        ArrayList<Integer> plist = new ArrayList<Integer>();
        plist.add(1);
        int n = 1;
        int flag;
        while(true){
            int gk = 1;
            int i = 0;
            plist.add(0);
            while(gk<=n){
                flag = (i%4>1)?-1:1;
                plist.set(n,plist.get(n)+flag*plist.get(n-gk));
                plist.set(n,plist.get(n)%limit);
                i++;
                int  k= (i%2==0)?i/2+1:-(i/2+1);
                gk = k*(3*k-1)/2;
            }

            if(plist.get(n)==0)
                break;
            n++;
        }
        System.out.println(n);
    }
//    55374
//    running time=1s155ms

    public static void main(String[] args){
        long t0 = System.currentTimeMillis();
        new PE078().run();
        long t1 = System.currentTimeMillis();
        long t = t1 - t0;
        System.out.println("running time="+t/1000+"s"+t%1000+"ms");

    }
}

法三:

又给出了求k的一种方式

关键程序:

while True:
            gk = k * (3 * k - 1) // 2
            i = n - gk
            if i < 0:
                break
            pt += (-1) ** (k * k + 1) * p[i]
            k = -1 * k if k > 0 else 1 - k
        p.append(pt)

python程序:

import time ;

def partitions(limit):
    p = [1, 1, 2]
    n = 2
    while True:
        n += 1
        pt = 0
        i = 0
        k = 1
        while True:
            gk = k * (3 * k - 1) // 2
            i = n - gk
            if i < 0:
                break
            pt += (-1) ** (k * k + 1) * p[i]
            k = -1 * k if k > 0 else 1 - k
        p.append(pt)
        if pt % limit == 0:
            print "n =", n, "\n"+"partition =", pt
            break

if __name__==‘__main__‘:
    t0 = time.time()
    limit = 1000000
    partitions(limit)
    t1 = time.time()
    print "running time=",(t1-t0),"s"

# n = 55374
# running time= 21.3049998283 s

说明:只有第一种方法是我自己写的,其他是在论坛看到的,自己整理的

时间: 2024-12-23 04:17:24

Project Euler 78:Coin partitions的相关文章

Project Euler:Problem 78 Coin partitions

Let p(n) represent the number of different ways in which n coins can be separated into piles. For example, five coins can be separated into piles in exactly seven different ways, so p(5)=7. OOOOO OOOO   O OOO   OO OOO   O   O OO   OO   O OO   O   O 

Python练习题 048:Project Euler 021:10000以内所有亲和数之和

本题来自 Project Euler 第21题:https://projecteuler.net/problem=21 ''' Project Euler: Problem 21: Amicable numbers Let d(n) be defined as the sum of proper divisors of n (numbers less than n which divide evenly into n). If d(a) = b and d(b) = a, where a ≠ b

Python练习题 047:Project Euler 020:阶乘结果各数字之和

本题来自 Project Euler 第20题:https://projecteuler.net/problem=20 ''' Project Euler: Problem 20: Factorial digit sum n! means n × (n ? 1) × ... × 3 × 2 × 1 For example, 10! = 10 × 9 × ... × 3 × 2 × 1 = 3628800, and the sum of the digits in the number 10! i

Python练习题 046:Project Euler 019:每月1日是星期天

本题来自 Project Euler 第19题:https://projecteuler.net/problem=19 ''' How many Sundays fell on the first of the month during the twentieth century (1 Jan 1901 to 31 Dec 2000)? Answer: 171 ''' from datetime import * firstDay = date(1901,1,1) lastDay = date(

Python练习题 035:Project Euler 007:第10001个素数

本题来自 Project Euler 第7题:https://projecteuler.net/problem=7 # Project Euler: Problem 7: 10001st prime # By listing the first six prime numbers: # 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13. # What is the 10 001st prime number? # Answer

Python练习题 034:Project Euler 006:和平方与平方和之差

本题来自 Project Euler 第6题:https://projecteuler.net/problem=6 # Project Euler: Problem 6: Sum square difference # The sum of the squares of the first ten natural numbers is, # 1**2 + 2**2 + ... + 10**2 = 385 # The square of the sum of the first ten natur

Project Euler 126 - Cuboid layers

这题先是推公式- 狂用不完全归纳+二次回归,最后推出这么一个奇怪的公式 f(t,x,y,z)=4(t?1)(x+y+z+t?2)+2(xy+yz+xz) 表示长宽高为x .y .z 的立方体第t 层放的立方体的个数. 接下来就是算答案了- 方法很简单:暴力 但是暴力还是有技巧的,开始我是直接从1到1000枚举t .x .y .z ,但这样出不来结果. 换成下面代码里的方法就行了. 1 #include <iostream> 2 #include <cstdio> 3 #includ

Project Euler 第一题效率分析

Project Euler: 欧拉计划是一系列挑战数学或者计算机编程问题,解决这些问题需要的不仅仅是数学功底. 启动这一项目的目的在于,为乐于探索的人提供一个钻研其他领域并且学习新知识的平台,将这一平台打造一个有趣和休闲 的环境. 项目主页:https://projecteuler.net 第一题 Multiples of 3 and 5 If we list all the natural numbers below 10 that are multiples of 3 or 5, we ge

Python练习题 042:Project Euler 014:最长的考拉兹序列

本题来自 Project Euler 第14题:https://projecteuler.net/problem=14 ''' Project Euler: Problem 14: Longest Collatz sequence The following iterative sequence is defined for the set of positive integers: n → n/2 (n is even) n → 3n + 1 (n is odd) Using the rule