Project Euler 271
@see http://projecteuler.net/index.php?section=problems&id=271
♥0 |
Line 366 |
Modified 2010-01-03 02:40:07 |
MIT License
archived:2017-03-30 04:43:03
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/b5L3
*/
package {
import flash.display.Sprite;
import flash.text.TextField;
import flash.utils.getTimer;
// @see http://projecteuler.net/index.php?section=problems&id=271
public class Euler271 extends Sprite {
private var _tf : TextField;
public function Euler271() {
_tf = new TextField();
_tf.width = 465;
_tf.height = 465;
addChild(_tf);
var s : int = getTimer();
tr(solve());
var g : int = getTimer();
tr((g - s) + " ms");
}
private const N : Number = 13082761331670030;
// private const N : Number = 91;
// x^3=1(mod N)なら、Nの素因数pについても
// x^3=1(mod p)のはず。これを満たすxをすべてのpについて探して
// 中国剰余定理を使って?mod Nでの値を列挙して和を出す。
// 問題文にあるドでかい数は2~43の素数の積なので楽。
//
// だがASだとNumberの精度では計算しきれないので工夫が必要。
private function solve() : MPI
{
tr("N", N);
var f : Object = factorize(N);
var i : uint;
var rs : Array = [new MPI(0)];
var div : Number = 1;
var r : MPI;
for(var key : String in f){
var p : uint = uint(key);
var a : Array = [];
_exg = exGCD(div, p);
for(i = 1;i < p;i++){
if((i * i * i) % p == 1){
for each(r in rs){
var c : MPI = chinese(r.toNumber(), i, div, p);
a.push(c);
}
}
}
div *= p;
rs = a;
}
tr(rs.join('\n'));
tr(rs.length);
var sum : MPI = new MPI();
var rm : MPI;
for each(rm in rs){
if(MPI.comp(rm, new MPI(1)) > 0)sum.add_(rm);
}
return sum;
}
private var _exg : Array;
private function chinese(a1 : Number, a2 : Number, m1 : Number, m2 : Number) : MPI
{
if(_exg[0] != 1)return new MPI(0);
var m12 : MPI = MPI.mul(new MPI(m1), new MPI(m2));
var ret : MPI;
// ((a2-a1)*_exg[1]*m1)%(m1*m2)を[0, m1*m2)の範囲で求める。ただし割られる数は負にもなり得て、さらにNumberの精度を上回る。
var r : Number;
var positive : Boolean = ((a2 - a1) * _exg[1] >= 0);
var mpi : MPI = MPI.mul(MPI.mul(new MPI(Math.abs(a2 - a1)), new MPI(Math.abs(_exg[1]))), new MPI(m1));
mpi = MPI.div(mpi, m12)[1];
if(!positive){
mpi = MPI.sub(m12, mpi);
}
mpi.add_(new MPI(a1));
if(MPI.comp(mpi, m12) >= 0){
mpi.sub_(m12);
}
return mpi;
}
private function exGCD(a : Number, b : Number) : Array
{
var p : Number = 1, q : Number = 0;
var r : Number = 0, s : Number = 1;
while(b > 0){
var c : Number = Math.floor(a / b);
var d : Number = a;
a = b;
b = d - c * b;
d = p;
p = q;
q = d - c * q;
d = r;
r = s;
s = d - c * s;
}
return [a, p, r];
}
private function factorize(n : Number) : Object
{
var ret : Object = {};
var sq : int = Math.sqrt(n);
for(var i : int = 2;i <= sq;i++){
var ct : int = 0;
while(n % i == 0){
n /= i;
ct++;
}
if(ct > 0){
ret[i] = ct;
sq = Math.sqrt(n);
}
}
if(n != 1){
ret[n] = 1;
}
return ret;
}
private function tr(...o : Array) : void
{
_tf.appendText(o + "\n");
_tf.scrollV = _tf.maxScrollV;
}
}
}
class MPI
{
public var d : Vector.<uint>;
public function MPI(v : * = 0)
{
if(v is Number){
d = Vector.<uint>([]);
for(var n : Number = v;n != 0;n = Math.floor(n / 10))d.push(n % 10);
if(v == 0)d.push(0);
}else if(v is String){
d = Vector.<uint>([]);
for(var i : int = v.length - 1;i >= 0;i--){
d.push(uint(v.charAt(i)));
}
}else if(v is Array){
d = Vector.<uint>(v);
}else if(v is Vector.<uint>){
d = v.concat();
}else if(v is MPI){
d = v.d.concat();
}
if(d)shave();
}
public static function add(a : MPI, b : MPI) : MPI
{
if(b == null)return a;
var ret : MPI = new MPI(a);
var i : uint;
var minl : uint = Math.min(ret.d.length, b.d.length);
for(i = 0;i < minl;i++){
ret.d[i] += b.d[i];
}
for(i = ret.d.length;i < b.d.length;i++){
ret.d.push(b.d[i]);
}
ret.carry();
return ret;
}
public function add_(b : MPI) : MPI
{
if(b == null)return this;
var i : uint;
var minl : uint = Math.min(this.d.length, b.d.length);
for(i = 0;i < minl;i++){
this.d[i] += b.d[i];
}
for(i = this.d.length;i < b.d.length;i++){
this.d.push(b.d[i]);
}
this.carry();
return this;
}
public static function addint(a : MPI, b : int) : MPI
{
var ret : MPI = new MPI(a);
ret.d[0] += b;
ret.carry();
return ret;
}
public function addint_(b : int) : MPI
{
this.d[0] += b;
this.carry();
return this;
}
public function inc() : void
{
d[0]++;
for(var i : uint = 0;i < d.length;i++){
if(d[i] >= 10){
var c : uint = d[i] / 10;
if(i == d.length - 1){
d.push(0);
}
d[i + 1] += c;
d[i] %= 10;
}else{
break;
}
}
}
public static function sub(a: MPI, b : MPI) : MPI
{
if(b == null)return a;
if(comp(a, b) < 0){
var m : MPI = a; a = b; b = m;
}
// a - b
var ret : MPI = new MPI(a);
var i : uint;
for(i = 0;i < b.d.length;i++){
ret.d[i] -= b.d[i];
}
ret.minuscarry();
return ret;
}
public function sub_(b : MPI) : MPI
{
if(b == null)return this;
// a - b
var i : uint;
for(i = 0;i < b.d.length;i++){
this.d[i] -= b.d[i];
}
this.minuscarry();
return this;
}
public static function subint(a : MPI, b : int) : MPI
{
var ret : MPI = new MPI(a);
ret.d[0] -= b;
ret.minuscarry();
return ret;
}
public function subint_(b : int) : MPI
{
this.d[0] -= b;
this.minuscarry();
return this;
}
public static function comp(a : MPI, b : MPI) : int
{
if(a.d.length != b.d.length)return a.d.length - b.d.length;
for(var i : int = a.d.length - 1;i >= 0;i--){
if(a.d[i] != b.d[i]){
return a.d[i] - b.d[i];
}
}
return 0;
}
public static function mul(a : MPI, b : MPI) : MPI
{
var retv : Vector.<uint> = new Vector.<uint>(a.d.length + b.d.length);
var i : uint, j : uint;
for(i = 0;i < retv.length;i++)retv[i] = 0;
for(i = 0;i < a.d.length;i++){
for(j = 0;j < b.d.length;j++){
retv[i + j] += a.d[i] * b.d[j];
}
}
var ret : MPI = new MPI(retv);
ret.carry();
ret.shave();
return ret;
}
public static function mulint(a : MPI, b : int) : MPI
{
var ret : MPI = new MPI(a);
for(var i : uint = 0;i < ret.d.length;i++){
ret.d[i] *= b;
}
ret.carry();
return ret;
}
public function mulint_(b : int) : MPI
{
for(var i : uint = 0;i < d.length;i++){
this.d[i] *= b;
}
this.carry();
return this;
}
public static function div(a : MPI, b : MPI) : Array
{
var bm : Array = new Array(10);
var i : int, j : uint;
for(i = 1;i <= 9;i++)bm[i] = mulint(b, i);
var retr : Vector.<uint> = Vector.<uint>([]);
var m : MPI = new MPI(0);
for(i = a.d.length - 1;i >= 0;i--){
m.mul10(1);
m = addint(m, a.d[i]);
for(j = 1;j <= 9;j++){
if(comp(m, bm[j]) < 0)break;
}
retr.push(j - 1);
if(j >= 2)m.sub_(bm[j - 1]);
}
var ret : MPI = new MPI(retr.reverse());
ret.shave();
m.shave();
return [ret, m];
}
public static function divint(a : MPI, b : int) : Array
{
var i : int;
var retr : Vector.<uint> = Vector.<uint>([]);
var m : int = 0;
for(i = a.d.length - 1;i >= 0;i--){
m = m * 10 + a.d[i];
var dv : int = m / b;
retr.push(dv);
m %= b;
}
var ret : MPI = new MPI(retr.reverse());
ret.shave();
return [ret, m];
}
// 末尾の0の個数
public function nLast0() : int
{
for(var i : uint = 0;i < d.length && d[i] == 0;i++);
return i;
}
// 位上げ
public function carry() : void
{
for(var i : uint = 0;i < d.length;i++){
if(d[i] >= 10){
var c : uint = d[i] / 10;
if(i == d.length - 1){
d.push(0);
}
d[i + 1] += c;
d[i] %= 10;
}
}
}
// 位下げ
public function minuscarry() : void
{
for(var i : uint = 0;i < d.length;i++){
if(d[i] <= 2147483648)continue; // やっつけ
var v : int = d[i] - 4294967296;
var c : int = (-v + 9) / 10;
d[i + 1] -= c;
d[i] += 10 * c;
}
shave();
}
// 上位の桁から0を削る
public function shave() : void
{
for(var i : uint = d.length - 1;i >= 1;i--){
if(d[i] > 0)break;
d.pop();
}
}
public function mul10(x : int) : void
{
var r : Vector.<uint> = d.reverse();
for(var i : uint = 0;i < x;i++){
r.push(0);
}
d = r.reverse();
}
public function isZero() : Boolean
{
return d.length == 1 && d[0] == 0;
}
public function toNumber() : Number
{
return Number(toString());
}
public function toString() : String
{
return d.concat().reverse().join('');
}
}