flash on 2009-10-12

by uwi
@see http://projecteuler.net/index.php?section=problems&id=
♥0 | Line 152 | Modified 2009-10-13 04:39:04 | MIT License
play

ActionScript3 source code

/**
 * Copyright uwi ( http://wonderfl.net/user/uwi )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/nbKK
 */

package {
    import flash.display.Sprite;
    import flash.text.TextField;
    import flash.utils.getTimer;
    // @see http://projecteuler.net/index.php?section=problems&id=
    public class Euler extends Sprite {
        private var _tf : TextField;
  
        // Euler Problem 258の予定
        public function Euler() {
            _tf = new TextField();
            _tf.width = 465;
            _tf.height = 465;
            addChild(_tf);
            
            var s : int = getTimer();
            tr(solve());
//            tr(exGCD(2008,2002));
            var g : int = getTimer();
            tr((g - s) + " ms");
        }

        private function solve() : int
        {
            var N : Number = Math.pow(10, 18);
            var M0 : Number = 500000000000000; // 係数パスカル三角形の左端の長さ
            var M1 : Number = Math.floor(N / 1999); // 係数パスカル三角形の右端の長さ
            
            var n2000 : Number = M1 / 2000; // 2000列の個数
            var mod : int = (n2000 - Math.floor(n2000)) * 2000; // テーブルの周回数の余りのユニットの余りの長さ
            n2000 = Math.floor(n2000);
            tr(M1, n2000);
            
            var ret : int = 0;
            var mul : int = 1;
            
            var p : int;
            var sum : int;
            var i : int, j : int;
            
            for each(p in [2, 5]){
                var modp : int = modd(n2000, p);
                var t : Array = cmodtable(p);
                sum = 0;
                
                sum += t[(modp - 1) * p + 0];
                for(j = 1;j < mod;j++){
                    sum += t[modp * p + (j % p)];
                }
                sum %= p;
                tr(p, modp, sum);
                ret = chinese(ret, sum, mul, p);
                mul *= p;
            }
            tr(ret);
                 
            // 20092010 = 2 * 5 * 859 * 2339
            for each(p in [859, 2339]){
                var rep : Number = n2000 / p; // テーブルの周回数
                var rep2 : int = modd(n2000, p);
                 
                var t : Array = cmodtable(p);
                
                // ユニットをつくる
                // 1周をつくる
                var cir : int = 0;
                var d2 : int = 2000 / p;
                var m2 : int = 2000 % p;
                for(i = 0;i < p;i++){
                    var mi : int = i * p;
                    var start : int = (i * 2000) % p;
                    
                    cir += exmod(2, i, p) * d2;
                    for(j = 0;j < m2;j++){
                        cir += t[mi + ((start + j) % p)];
                    }
                    cir %= p;
                }
                var sum : int = (cir * modd(Math.floor(rep), p)) % p;
                tr(p, Math.floor(rep), rep2, mod, cir, sum);
                
                d2 = 2000 / p;
                m2 = 2000 % p;
                for(i = 0;i < rep2;i++){
                    mi = i * p;
                    start = (i * 2000) % p;
                    
                    sum += exmod(2, i, p) * d2;
                    for(j = 0;j < m2;j++){
                        sum += t[mi + ((start + j) % p)];
                    }
                    sum %= p;
                }
//                sum = sum + t[0] - t[(i - 1) * p + (((i - 1) * 2000) % p)];
                
                // ユニットの余りを作る
                d2 = mod / p;
                m2 = mod % p;
                mi = (i % p) * p;
                start = (i * 2000) % p;
                
                sum += t[(mi - p) + start];
                sum += exmod(2, i % p, p) * d2;
                for(j = 1;j < m2;j++){
                    sum += t[mi + ((start + j) % p)];
                }
                sum %= p;
                tr(p, sum);
                
                ret = chinese(ret, sum, mul, p);
                mul *= p;
            }
            return ret;
        } 
        
        private function chinese(a1 : int, a2 : int, m1 : int, m2 : int) : Number
        {
            var e : Array = exGCD(m1, m2);
            if(e[0] != 1)return 0;
            for(var ret : Number = a1 + (a2 - a1) * e[1] * m1;ret < 0;ret += m1 * m2);
            return ret;
        }
        
        // (a,b)=1のときの、ax+by=1の解
        private function exGCD(a : int, b : int) : Array
        {
            return rec(a, b, 1, 0, 0, 1);
        }
        
        private function rec(a : int, b : int, p : int, q : int, r : int, s : int) : Array
        {
            if(b == 0)return [a, p, r];
            var c : int = a / b;
            return rec(b, a % b, q, p - c * q, s, r - c * s);
        }
        
        // a : prime
        // C(n, k) % aのテーブル(n<kのときは0)
        private function cmodtable(a : int) : Array
        {
            var invs : Array = new Array(a);
            for(var i : int = 1;i < a;i++){
                invs[i] = inv(i, a);
            }
         
            var ret : Array = new Array(a * a);
            for(var r : int = 0;r < a;r++){
                var v : int = 1;
                for(var c : int = 0;c < a;c++){
                    ret[r * a + c] = c > r ? 0 : v;
                    v = (v * (r - c)) % a;
                    v = (v * invs[c + 1]) % a;
                }
            }
            
            return ret;
        }
        
        // p : prime
        private function inv(n : int, p : int) : int
        {
            // p-2乗する
            return exmod(n, p - 2, p);
        }
        
        // a^n(mod p) ただし a<2^16
        private function exmod(a : int, n : int, p : int) : int
        {
            var mul : int = a;
            var ret : int = 1;
            for(var i : int = n;i > 0;i >>= 1){
                if((i & 1) == 1){
                    ret *= mul;
                    ret %= p;
                }
                mul *= mul;
                mul %= p;
            }
            return ret;
        }
        
        private function modd(a : Number, b : int) : int
        {
            var r : Number = a / b;
            return int(Math.round((r - Math.floor(r)) * b));
        }

        private function tr(...o : Array) : void
        {
            _tf.appendText(o + "\n");
        }
    }
}