Problem:
Score : 400 points

Problem Statement

You are given an integer N. Find the number of strings of length N that satisfy the following conditions, modulo 10^9+7:

The string does not contain characters other than A, C, G and T.

The string does not contain AGC as a substring.

The condition above cannot be violated by swapping two adjacent characters once.

Notes

A substring of a string T is a string obtained by removing zero or more characters from the beginning and the end of T.

For example, the substrings of ATCODER include TCO, AT, CODER, ATCODER and (the empty string), but not AC.

Constraints

3 \leq N \leq 100

Input

Input is given from Standard Input in the following format:

N

Output

Print the number of strings of length N that satisfy the following conditions, modulo 10^9+7.

Sample Input 1

3

Sample Output 1

61

There are 4^3 = 64 strings of length 3 that do not contain characters other than A, C, G and T. Among them, only AGC, ACG and GAC violate the condition, so the answer is 64 - 3 = 61.

Sample Input 2

4

Sample Output 2

230

Sample Input 3

100

Sample Output 3

388130742

Be sure to print the number of strings modulo 10^9+7.

Solution in C# (Mono 4.6.2.0) (judge verdict: Accepted)

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


partial class Solver {
    const int A = 1;
    const int C = 2;
    const int G = 3;
    const int T = 4;
    public void Run() {
        var n = ni();

        var dp = new int[5, 5, 5]; // pre3, pre2, pre1
        dp[0, 0, 0] = 1;
        int mod = 1000000000 + 7;
        for (int i = 0; i < n; i++) {
            var next = new int[5, 5, 5]; // pre3, pre2, pre1
            for (int c = 1; c <= 4; c++) {
                for (int pre3 = 0; pre3 < 5; pre3++) {
                    for (int pre2 = 0; pre2 < 5; pre2++) {
                        for (int pre1 = 0; pre1 < 5; pre1++) {

                            if (pre2 == A && pre1 == G && c == C) continue; // AGC

                            if (pre2 == G && pre1 == A && c == C) continue; // GAC
                            if (pre2 == A && pre1 == C && c == G) continue; // ACG

                            if (pre3 == A && pre2 != 0 && pre1 == G && c == C) continue; // A*GC
                            if (pre3 == A && pre2 == G && pre1 != 0 && c == C) continue;// AG*C

                            next[pre2, pre1, c] += dp[pre3, pre2, pre1];
                            next[pre2, pre1, c] %= mod;
                        }
                    }
                }
            }
            dp = next;
        }
        var ans = dp.Cast<int>().Sum(a => (long)a);
        cout.WriteLine(ans % mod);
    }
}

public class PriorityQueue<T> {
    private T[] array = new T[100];
    private int size = 0;
    private readonly Comparer<T> _comparer;

    public PriorityQueue() {
        _comparer = Comparer<T>.Default;
    }

    public PriorityQueue(Comparison<T> comp) {
        _comparer = Comparer<T>.Create(comp);
    }

    public int Count { get { return size; } }

    private void Swap(int a, int b) {
        var t = array[a];
        array[a] = array[b];
        array[b] = t;
    }

    private void Expand() {
        var newlist = new T[array.Length * 2];
        Array.Copy(array, newlist, array.Length);
        array = newlist;
    }

    public bool Any() {
        return size > 0;
    }

    public void Enqueue(T newValue) {
        if (size >= array.Length) {
            Expand();
        }
        array[size++] = newValue;
        int pos = size - 1;
        while (pos > 0) {
            int parent = (pos - 1) / 2;
            if (_comparer.Compare(array[parent], array[pos]) > 0) {
                Swap(parent, pos);
                pos = parent;
            } else {
                break;
            }
        }
    }

    public T Peek() {
        return array[0];
    }

    public T Dequeue() {
        var top = array[0];
        array[0] = array[--size];
        int pos = 0;
        while (pos * 2 + 1 < size) {
            int left = pos * 2 + 1;
            int right = left + 1;
            int next = left;
            if (right < size && _comparer.Compare(array[left], array[right]) > 0) {
                next = right;
            }

            if (_comparer.Compare(array[pos], array[next]) > 0) {
                Swap(next, pos);
                pos = next;
            } else {
                break;
            }
        }

        return top;
    }
};



// PREWRITEN CODE BEGINS FROM HERE
partial class Solver : Scanner {
    public static void Main(string[] args) {
        new Solver(Console.In, Console.Out).Run();
    }

    TextReader cin;
    TextWriter cout;

    public Solver(TextReader reader, TextWriter writer)
        : base(reader) {
        this.cin = reader;
        this.cout = writer;
    }
    public Solver(string input, TextWriter writer)
        : this(new StringReader(input), writer) {
    }

    public int ni() { return NextInt(); }
    public int[] ni(int n) { return NextIntArray(n); }
    public long nl() { return NextLong(); }
    public long[] nl(int n) { return NextLongArray(n); }
    public double nd() { return NextDouble(); }
    public string ns() { return Next(); }
}

public class Scanner {
    private TextReader Reader;
    private Queue<String> TokenQueue = new Queue<string>();
    private CultureInfo ci = CultureInfo.InvariantCulture;

    public Scanner()
        : this(Console.In) {
    }

    public Scanner(TextReader reader) {
        this.Reader = reader;
    }

    public int NextInt() { return Int32.Parse(Next(), ci); }
    public long NextLong() { return Int64.Parse(Next(), ci); }
    public double NextDouble() { return double.Parse(Next(), ci); }
    public string[] NextArray(int size) {
        var array = new string[size];
        for (int i = 0; i < size; i++) array[i] = Next();
        return array;
    }
    public int[] NextIntArray(int size) {
        var array = new int[size];
        for (int i = 0; i < size; i++) array[i] = NextInt();
        return array;
    }

    public long[] NextLongArray(int size) {
        var array = new long[size];
        for (int i = 0; i < size; i++) array[i] = NextLong();
        return array;
    }

    public String Next() {
        if (TokenQueue.Count == 0) {
            if (!StockTokens()) throw new InvalidOperationException();
        }
        return TokenQueue.Dequeue();
    }

    public bool HasNext() {
        if (TokenQueue.Count > 0)
            return true;
        return StockTokens();
    }

    private bool StockTokens() {
        while (true) {
            var line = Reader.ReadLine();
            if (line == null) return false;
            var tokens = line.Trim().Split(" ".ToCharArray(), StringSplitOptions.RemoveEmptyEntries);
            if (tokens.Length == 0) continue;
            foreach (var token in tokens)
                TokenQueue.Enqueue(token);
            return true;
        }
    }
}