Codingame『Bender - Algorithmic Complexity』

The Order: 1886初回生産限定 コスチューム3種、武器2種、戦闘アイテム2種をダウンロードできるプロダクトコード同梱
 気が変わって難易度:ハードの一番下にある問題をやってみた。
データの説明に最も適する近似曲線は何ですか?という問題。


 自分で作ってて思ったけど、超クソコードです。テストは通ったんですけどね。
どうしたらもっと綺麗に書けるんだろうなぁ……。
一回のループで全部の傾きと切片を得て、R2値をザッと計算するのが早いんだろうけど。
メモリがっつり食べたりしないだろうか…。気にし過ぎかな。


一応、恥をさらす意味で置いておきます。


using System;
using System.Linq;
using System.IO;
using System.Text;
using System.Collections;
using System.Collections.Generic;

/**
 * Auto-generated code below aims at helping you parse
 * the standard input according to the problem statement.
 **/
class Solution
{
    static void Main(string[] args)
    {
        int n = int.Parse(Console.ReadLine());
        int[] d_x = new int[n];
        int[] d_y = new int[n];
        double ave_num = 0;
        double ave_t = 0;

        Console.Error.WriteLine("N:{0}", n);
        
        for (int i = 0; i < n; i++)
        {
            string[] inputs = Console.ReadLine().Split(' ');
            int num = int.Parse(inputs[0]);
            int t = int.Parse(inputs[1]);
            Console.Error.WriteLine("{0} {1}", num, t);
            
            d_x[i] = num;
            d_y[i] = t;
            ave_num += (double)num;
            ave_t += (double)t;
        }
        ave_num = ave_num/(double)n;
        ave_t = ave_t/(double)n;
        Console.Error.WriteLine("average_num:{0}", ave_num);
        Console.Error.WriteLine("average_t:{0}", ave_t);
        
        string result = "";
        double ch = 0;
        double r = 0;
        ch = ErLogN(d_x, d_y);
        if(ch > r) {
            result = "O(log n)";
            r = ch;
        }
        ch = ER_N(d_x, d_y);
        if(ch > r) {
            result = "O(n)";
            r = ch;
        }
        ch = ErNLogN(d_x, d_y);
        if(ch > r) {
            result = "O(n log n)";
            r = ch;
        }
        ch = ErN2(d_x, d_y);
        if(ch > r) {
            result = "O(n^2)";
            r = ch;
        }
        ch = ErN2LogN(d_x, d_y);
        if(ch > r) {
            result = "O(n^2 log n)";
            r = ch;
        }
        ch = ErN3(d_x, d_y);
        if(ch > r) {
            result = "O(n^3)";
            r = ch;
        }
        ch = Er2N(d_x, d_y);
        if(ch > r) {
            result = "O(2^n)";
            r = ch;
        }
        if(r < 0.8) {
            result = "O(1)";
            r = ch;
        }
        // Write an action using Console.WriteLine()
        // To debug: Console.Error.WriteLine("Debug messages...");

        Console.WriteLine(result);
    }
    
    //O(1)
    static double Er1(int[] d_x, int[] d_y)
    {
        double[] nx = new double[d_x.Length];
        double sumxx = 0;
        double sumxy = 0;
        double sumx = 0;
        double sumy = 0;
        for(int n = 0; n < d_x.Length; n++) {
            nx[n] = 1.0;
            sumxy += nx[n]*(double)d_y[n];
            sumxx += nx[n]*nx[n];
            sumx += nx[n];
            sumy += (double)d_y[n];
        }
        double t = sumxx * (double)(d_x.Length) - sumx * sumx;
        double a = (sumxy * (double)(d_x.Length) - sumx*sumy) / t;
        double b = (sumxx * sumy - sumxy * sumx) / t;
        Console.Error.WriteLine("[1]{0}x + {1}", a, b);
        
        a = 0;
        b = sumy / (double)(d_x.Length);
        return CoefficientOfDetermination(nx, d_y, sumy, a, b);
    }
    
    //O(log(n))
    static double ErLogN(int[] d_x, int[] d_y)
    {
        double[] nx = new double[d_x.Length];
        double sumxx = 0;
        double sumxy = 0;
        double sumx = 0;
        double sumy = 0;
        for(int n = 0; n < d_x.Length; n++) {
            nx[n] = Math.Log((double)d_x[n]);
            sumxy += nx[n]*(double)d_y[n];
            sumxx += nx[n]*nx[n];
            sumx += nx[n];
            sumy += (double)d_y[n];
        }
        double t = sumxx * (double)(d_x.Length) - sumx * sumx;
        double a = (sumxy * (double)(d_x.Length) - sumx*sumy) / t;
        double b = (sumxx * sumy - sumxy * sumx) / t;
        Console.Error.WriteLine("[2]{0}x + {1}", a, b);

/*
        double avey = sumy/(double)(d_y.Length);
        double sump1 = 0;
        double sump2 = 0;
        double r2 = 0;
        for(int n = 0; n < d_y.Length; n++) {
            double tmp = (double)d_y[n] - (a * nx[n] + b);
            sump1 += (tmp * tmp);
            tmp = (double)d_y[n] - avey;
            sump2 += tmp * tmp;
        }
        r2 = 1.0 - (sump1 / sump2);

        Console.Error.WriteLine("R2 = {0}", r2);
        
        return r2;
*/
        return CoefficientOfDetermination(nx, d_y, sumy, a, b);
    }

    //O(n)
    static double ER_N(int[] d_x, int[] d_y)
    {
        double[] nx = new double[d_x.Length];
        double sumxx = 0;
        double sumxy = 0;
        double sumx = 0;
        double sumy = 0;
        for(int n = 0; n < d_x.Length; n++) {
            nx[n] = (double)d_x[n];
            sumxy += nx[n]*(double)d_y[n];
            sumxx += nx[n]*nx[n];
            sumx += nx[n];
            sumy += (double)d_y[n];
        }
        double t = sumxx * (double)(d_x.Length) - sumx * sumx;
        double a = (sumxy * (double)(d_x.Length) - sumx*sumy) / t;
        double b = (sumxx * sumy - sumxy * sumx) / t;
        Console.Error.WriteLine("[3]{0}x + {1}", a, b);

        return CoefficientOfDetermination(nx, d_y, sumy, a, b);
    }

    //O(n * log(n))
    static double ErNLogN(int[] d_x, int[] d_y)
    {
        double[] nx = new double[d_x.Length];
        double sumxx = 0;
        double sumxy = 0;
        double sumx = 0;
        double sumy = 0;
        for(int n = 0; n < d_x.Length; n++) {
            nx[n] = (double)d_x[n] * Math.Log((double)d_x[n]);
            sumxy += nx[n]*(double)d_y[n];
            sumxx += nx[n]*nx[n];
            sumx += nx[n];
            sumy += (double)d_y[n];
        }
        double t = sumxx * (double)(d_x.Length) - sumx * sumx;
        double a = (sumxy * (double)(d_x.Length) - sumx*sumy) / t;
        double b = (sumxx * sumy - sumxy * sumx) / t;
        Console.Error.WriteLine("[4]{0}x + {1}", a, b);

        return CoefficientOfDetermination(nx, d_y, sumy, a, b);
    }
    
    //O(n^2)
    static double ErN2(int[] d_x, int[] d_y)
    {
        double[] nx = new double[d_x.Length];
        double sumxx = 0;
        double sumxy = 0;
        double sumx = 0;
        double sumy = 0;
        for(int n = 0; n < d_x.Length; n++) {
            nx[n] = Math.Pow((double)d_x[n], 2.0);
            sumxy += nx[n]*(double)d_y[n];
            sumxx += nx[n]*nx[n];
            sumx += nx[n];
            sumy += (double)d_y[n];
        }
        double t = sumxx * (double)(d_x.Length) - sumx * sumx;
        double a = (sumxy * (double)(d_x.Length) - sumx*sumy) / t;
        double b = (sumxx * sumy - sumxy * sumx) / t;
        Console.Error.WriteLine("[5]{0}x + {1}", a, b);

        return CoefficientOfDetermination(nx, d_y, sumy, a, b);
    }

    //O(n^2 * log(n))
    static double ErN2LogN(int[] d_x, int[] d_y)
    {
        double[] nx = new double[d_x.Length];
        double sumxx = 0;
        double sumxy = 0;
        double sumx = 0;
        double sumy = 0;
        for(int n = 0; n < d_x.Length; n++) {
            nx[n] = Math.Pow((double)d_x[n], 2.0) * Math.Log((double)d_x[n]);
            sumxy += nx[n]*(double)d_y[n];
            sumxx += nx[n]*nx[n];
            sumx += nx[n];
            sumy += (double)d_y[n];
        }
        double t = sumxx * (double)(d_x.Length) - sumx * sumx;
        double a = (sumxy * (double)(d_x.Length) - sumx*sumy) / t;
        double b = (sumxx * sumy - sumxy * sumx) / t;
        Console.Error.WriteLine("[6]{0}x + {1}", a, b);

        return CoefficientOfDetermination(nx, d_y, sumy, a, b);
    }

    //O(n^3)
    static double ErN3(int[] d_x, int[] d_y)
    {
        double[] nx = new double[d_x.Length];
        double sumxx = 0;
        double sumxy = 0;
        double sumx = 0;
        double sumy = 0;
        for(int n = 0; n < d_x.Length; n++) {
            nx[n] = Math.Pow((double)d_x[n], 3.0);
            sumxy += nx[n]*(double)d_y[n];
            sumxx += nx[n]*nx[n];
            sumx += nx[n];
            sumy += (double)d_y[n];
        }
        double t = sumxx * (double)(d_x.Length) - sumx * sumx;
        double a = (sumxy * (double)(d_x.Length) - sumx*sumy) / t;
        double b = (sumxx * sumy - sumxy * sumx) / t;
        Console.Error.WriteLine("[7]{0}x + {1}", a, b);

        return CoefficientOfDetermination(nx, d_y, sumy, a, b);
    }

    //O(2^n)
    static double Er2N(int[] d_x, int[] d_y)
    {
        double[] nx = new double[d_x.Length];
        double sumxx = 0;
        double sumxy = 0;
        double sumx = 0;
        double sumy = 0;
        for(int n = 0; n < d_x.Length; n++) {
            nx[n] = Math.Pow(2.0, (double)d_x[n]);
            sumxy += nx[n]*(double)d_y[n];
            sumxx += nx[n]*nx[n];
            sumx += nx[n];
            sumy += (double)d_y[n];
        }
        double t = sumxx * (double)(d_x.Length) - sumx * sumx;
        double a = (sumxy * (double)(d_x.Length) - sumx*sumy) / t;
        double b = (sumxx * sumy - sumxy * sumx) / t;
        Console.Error.WriteLine("[8]{0}x + {1}", a, b);

        double r = CoefficientOfDetermination(nx, d_y, sumy, a, b);
        if(r == double.NaN) return 0;
        else return r;
    }

    //未使用
    static double LinearRegression()
    {
        return 0;
    }
    
    //決定係数R2を求める
    static double CoefficientOfDetermination(double[] nx, int[] d_y, double sumy, double a, double b)
    {
        double avey = sumy/(double)(d_y.Length);
        double sump1 = 0;
        double sump2 = 0;
        double r2 = 0;
        for(int n = 0; n < d_y.Length; n++) {
            double tmp = (double)d_y[n] - (a * nx[n] + b);
            sump1 += (tmp * tmp);
            tmp = (double)d_y[n] - avey;
            sump2 += tmp * tmp;
        }
        r2 = 1.0 - (sump1 / sump2);

        Console.Error.WriteLine("R2 = {0}", r2);
        
        return r2;
    }
}