Problem:
Score : 300 points

Problem Statement

Given are positive integers N, M, Q, and Q quadruples of integers ( a_i , b_i , c_i , d_i ).

Consider a sequence A satisfying the following conditions:

A is a sequence of N positive integers.

1 \leq A_1 \leq A_2 \le \cdots \leq A_N \leq M.

Let us define a score of this sequence as follows:

The score is the sum of d_i over all indices i such that A_{b_i} - A_{a_i} = c_i. (If there is no such i, the score is 0.)

Find the maximum possible score of A.

Constraints

All values in input are integers.

2 ≤ N ≤ 10

1 \leq M \leq 10

1 \leq Q \leq 50

1 \leq a_i < b_i \leq N ( i = 1, 2, ..., Q )

0 \leq c_i \leq M - 1 ( i = 1, 2, ..., Q )

(a_i, b_i, c_i) \neq (a_j, b_j, c_j) (where i \neq j)

1 \leq d_i \leq 10^5 ( i = 1, 2, ..., Q )

Input

Input is given from Standard Input in the following format:

N M Q
a_1 b_1 c_1 d_1
:
a_Q b_Q c_Q d_Q

Output

Print the maximum possible score of A.

Sample Input 1

3 4 3
1 3 3 100
1 2 2 10
2 3 2 10

Sample Output 1

110

When A = \{1, 3, 4\}, its score is 110. Under these conditions, no sequence has a score greater than 110, so the answer is 110.

Sample Input 2

4 6 10
2 4 1 86568
1 4 0 90629
2 3 0 90310
3 4 1 29211
3 4 3 78537
3 4 2 8580
1 2 1 96263
1 4 2 2156
1 2 0 94325
1 4 3 94328

Sample Output 2

357500

Sample Input 3

10 10 1
1 10 9 1

Sample Output 3

1

Solution in Java (OpenJDK 11.0.6) (judge verdict: Accepted)

import java.util.*;
import java.io.*;

	
public class Main {
	public static void main(String[] args) throws Exception {
		FastScanner sc = new FastScanner();
		PrintWriter out = new PrintWriter(System.out);
		
		int ln = sc.nextInt();
		int ma = sc.nextInt();
		int q = sc.nextInt();
		
		int[] a1s = new int[q];
		int[] b1s = new int[q];
		int[] difs = new int[q];
		int[] scores = new int[q];
		
		for(int i=0; i<q; i++){
			a1s[i] = sc.nextInt()-1;
			b1s[i] = sc.nextInt()-1;
			difs[i] = sc.nextInt();
			scores[i] = sc.nextInt();
		}
		
		int count=0;
		int[] as = new int[ln];
		fill(as,1);
		
		boolean[] bnull = new boolean[0];
		ArrayList<boolean[]> alofcombi = combi_enum(ln+ma-1,bnull,0,ma-1);
		
		int moving =0, score_this =0, ans=0;
	   	for(int i=0; i<alofcombi.size(); i++){
		    as[0]=1;
		    moving=0;
	   	    boolean[] tmp = alofcombi.get(i);
			for(int j=0; j<(ln+ma-1); j++){
			    if(tmp[j]){
			        as[moving]++;
			    }else{
			        moving++;
			        if(moving == ln) break;
			        as[moving] = as[moving-1];
			    }
			}
			score_this=0;
			for(int j=0; j<q; j++){
			    int dif = as[b1s[j]]-as[a1s[j]];
			    if(dif==difs[j]) score_this+=scores[j];
			}
			ans = max(score_this,ans);
	   	}
		out.println(ans);
		
		/*sc.next();
		int n_machine = sc.nextInt();
		int kinds_bread = sc.nextInt();
		int n_order = sc.nextInt();
		
		int ln_bom = sc.nextInt();
		int ln_combi = sc.nextInt();
		
		int[] machine_size = new int[n_machine];
		ArrayList<ArrayList<Integer>> holiday_dt = new ArrayList<>();
	   	for(int i=0; i<n_machine; i++){
	   	    ArrayList<Integer> al1 = new ArrayList<>();
			holiday_dt.add(al1);
	   	}
	   	
	   	for(int i=0; i<n_machine; i++){
		    sc.next();
	   	    int machine_num1 = sc.nextInt();
	   	    machine_size[i] = sc.nextInt();
	   	    int n_holiday1 = sc.nextInt();
			for(int j=0; j<n_holiday1; j++){
			    int holiday_a1 = sc.nextInt();
			    holiday_dt.get(machine_num1).add(holiday_a1);
			}
	   	}
	   	
	   	int[][] time2bake = new int[n_machine][kinds_bread];
	   	fill(time2bake,INF);
	   	int[][] ele_cost = new int[n_machine][kinds_bread];
	   	fill(ele_cost,INF);
		
	   	for(int i=0; i<ln_bom; i++){
		    sc.next();
	   	    int machine_num1 = sc.nextInt();
	   	    int bread_num1 = sc.nextInt();
	   	    time2bake[machine_num1][bread_num1] = sc.nextInt();
	   	    ele_cost[machine_num1][bread_num1] = sc.nextInt();
	   	}
		
		int[][][] time2change = new int[n_machine][kinds_bread][kinds_bread];
		fill(time2change,INF);
		int[][][] cost2change = new int[n_machine][kinds_bread][kinds_bread];
		fill(cost2change,INF);
		
	   	for(int i=0; i<ln_combi; i++){
		    sc.next();
	   	    int machine_num1 = sc.nextInt();
	   	    int bread_pre = sc.nextInt();
	   	    int bread_nex = sc.nextInt();
	   	    time2change[machine_num1][bread_pre][bread_nex] = sc.nextInt();
	   	    cost2change[machine_num1][bread_pre][bread_nex] = sc.nextInt();
	   	}
		
		int[] ordered_bread = new int[n_order];
		int[] startable_time = new int[n_order];
		int[] order_limit = new int[n_order];
		int[] ordered_amount = new int[n_order];
		int[] spiltable_amount = new int[n_order];
		int[] paid = new int[n_order];
		int[] awaited_time = new int[n_order];
		
	   	for(int i=0; i<n_order; i++){
		    sc.next();
	   	    int order_code1 = sc.nextInt();
	   	    ordered_bread[order_code1] = sc.nextInt();
	   	    startable_time[order_code1] = sc.nextInt();
	   	    order_limit[order_code1] = sc.nextInt();
	   	    ordered_amount[order_code1] = sc.nextInt();
	   	    spiltable_amount[order_code1] = sc.nextInt();
	   	    paid[order_code1] = sc.nextInt();
	   	    awaited_time[order_code1] = sc.nextInt();
	   	}*/
		
		
		out.flush();
	}
	
    private static ArrayList<boolean[]> combi_enum(int ln, boolean[] former, int now_pos, int rest){
        ArrayList<boolean[]> ans = new ArrayList<>();
        boolean[] ans1 = new boolean[former.length+1];
	   	for(int i=0; i<former.length; i++){
	   	    ans1[i] = former[i];
	   	}
        if(ln==(now_pos+1)){
            switch(rest){
                case 0:
                    ans1[former.length] = false;
                    ans.add(ans1);
                    break;
                case 1:
                    ans1[former.length] = true;
                    ans.add(ans1);
                    break;
            }
        }else{
            if(rest == 0){
                ans1[former.length] = false;
                ans.addAll(combi_enum(ln, ans1, now_pos+1, rest));
            }else{
                ans1[former.length] = false;
                ans.addAll(combi_enum(ln, ans1.clone(), now_pos+1, rest));
                ans1[former.length] = true;
                ans.addAll(combi_enum(ln, ans1.clone(), now_pos+1, rest-1));
            }
        }
        return ans;
    }

	private static int INF = (int)1e8;
	private static long INFL = (long)1e17;
	private static int e97 = (int)1e9 + 7;
	
	
	private static int abs(int a){
	    return (a>=0) ? a: -a;
	}
	private static long abs(long a){
	    return (a>=0) ? a: -a;
	}
	
	private static int min(int a, int b){
	    return (a>b) ? b : a;
	}
	private static long min(long a, long b){
	    return (a>b) ? b : a;
	}
	
	private static int max(int a, int b){
		return (a>b) ? a : b;
	}
	private static long max(long a, long b){
		return (a>b) ? a : b;
	}
	
	private static int minN(int... ins){
		int min = ins[0];
		for(int i=1; i<ins.length; i++){
			if(ins[i] < min) min = ins[i];
		}
		return min;
	}
	private static int maxN(int... ins){
		int max = ins[0];
		for(int i=1; i<ins.length; i++){
			if(ins[i] > max) max = ins[i];
		}
		return max;
	}
	private static long minN(long... ins){
		long min = ins[0];
		for(int i=1; i<ins.length; i++){
			if(ins[i] < min) min = ins[i];
		}
		return min;
	}
	private static long maxN(long... ins){
		long max = ins[0];
		for(int i=1; i<ins.length; i++){
			if(ins[i] > max) max = ins[i];
		}
		return max;
	}
	
	private static int minExAd(int[] dt, int ad){
	int min=Integer.MAX_VALUE;
		for(int i=0; i<dt.length; i++){
			if((i != ad) && (dt[i] < min)) min = dt[i];
		}
		return min;
	}
	private static long minExAd(long[] dt, int ad){
	long min=Long.MAX_VALUE;
		for(int i=0; i<dt.length; i++){
			if((i != ad) && (dt[i] < min)) min = dt[i];
		}
		return min;
	}
	private static int minExVal(int[] dt, int ex_val){
	int min=Integer.MAX_VALUE;
		for(int i=0; i<dt.length; i++){
			if((dt[i] != ex_val) && (dt[i] < min)) min = dt[i];
		}
		return min;
	}
	private static long minExVal(long[] dt, long ex_val){
	long min=Long.MAX_VALUE;
		for(int i=0; i<dt.length; i++){
			if((dt[i] != ex_val) && (dt[i] < min)) min = dt[i];
		}
		return min;
	}
	
	private static boolean same3(long a, long b, long c){
	if(a!=b) return false;
	if(b!=c) return false;
	if(c!=a) return false;
	return true;
	}
	private static boolean dif3(long a, long b, long c){
	if(a==b) return false;
	if(b==c) return false;
	if(c==a) return false;
	return true;
	}
	
	private static int factorial(int n) {
		int ans=1;
		for(int i=n; i>0; i--){
			ans*=i;
		}
		return ans;
	}
	
	private static long gcd(long m, long n) {
		if(m < n) return gcd(n, m);
		if(n == 0) return m;
		return gcd(n, m % n);
	}
	
	private static int pow2(int in){
		return in*in;
	}
	private static long pow2(long in){
		return in*in;
	}
	
	private static int getDigit2(long num){
		long cf = 1;
		int d=0;
		while(num >= cf){
			d++;
			cf = 1<<d;
		}
		return d; //numはd桁の数で、2^dより小さい
	}
	
	private static int getDigit10L(long num){
		long cf = 1;
		int d=0;
		while(num >= cf){
			d++;
			cf*=10;
		}
		return d; //numはd桁の数で、10^dより小さい
	}
	
	private static boolean isINF(int in){
	if((in*20)>INF) return true;
	else return false;
	}
	private static boolean isINFL(long in){
	if((in*10000)>INFL) return true;
	else return false;
	}
	
	private static long pow10E97(long ob, int soeji){
		if(soeji==2) return (ob*ob)%e97;
		
		int d = getDigit2(soeji);
		long[] ob_pow_2pow = new long[d];
		
		ob_pow_2pow[0] = ob;
		for(int i=1; i<d; i++){
			ob_pow_2pow[i] = (ob_pow_2pow[i-1]*ob_pow_2pow[i-1])%e97;
		}
		
		long ans=1;
		for(int i=d-1; i>=0; i--){
			if(soeji >= (1<<i)){
				soeji -= (1<<i);
				ans = (ans*ob_pow_2pow[i])%e97;
			}
 		}
		
		return ans;
	}
	
	
	private static int flag(int pos){
	    return (1<<pos);
	}
	private static boolean isFlaged(int bit, int pos){
    	if((bit&(1<<pos)) > 0) return true;
    	else return false;
	}
	private static int deflag(int bit, int pos){
	    return bit&~(1<<pos);
	}
	private static void showflag(int bit){
    	for(int i=0; i<getDigit2(bit); i++){
        	if(isFlaged(bit,i)) System.out.print("O");
        	else System.out.print(".");
    	}
	}
	
	
	private static void fill(boolean[] ob, boolean res){
		for(int i=0; i<ob.length; i++){
			ob[i] = res;
		}
		return;
	}
	private static void fill(int[] ob, int res){
		for(int i=0; i<ob.length; i++){
			ob[i] = res;
		}
		return;
	}
	private static void fill(long[] ob, long res){
		for(int i=0; i<ob.length; i++){
			ob[i] = res;
		}
		return;
	}
	private static void fill(char[] ob, char res){
		for(int i=0; i<ob.length; i++){
			ob[i] = res;
		}
		return;
	}
	private static void fill(int[][] ob, int res){
		for(int i=0; i<ob.length; i++){
			for(int j=0; j<ob[0].length; j++){
				ob[i][j] = res;
			}
		}
		return;
	}
	private static void fill(long[][] ob, long res){
		for(int i=0; i<ob.length; i++){
			for(int j=0; j<ob[0].length; j++){
				ob[i][j] = res;
			}
		}
		return;
	}
	private static void fill(char[][] ob, char res){
		for(int i=0; i<ob.length; i++){
			for(int j=0; j<ob[0].length; j++){
				ob[i][j] = res;
			}
		}
		return;
	}
	private static void fill(int[][][] ob, int res){
		for(int i=0; i<ob.length; i++){
			for(int j=0; j<ob[0].length; j++){
				for(int k=0; k<ob[0][0].length; k++){
			ob[i][j][k] = res;
				}
			}
		}
		return;
	}
	private static void fill(long[][][][] ob, long res){
		for(int i=0; i<ob.length; i++){
			for(int j=0; j<ob[0].length; j++){
				for(int k=0; k<ob[0][0].length; k++){
				for(int l=0; l<ob[0][0][0].length; l++){
				ob[i][j][k][l]=res;
				}
				}
			}
		}
		return;
	}
	
	static void show_b2d_array(boolean[][] dt, int lit_x, int lit_y){
		for(int i=0; i<dt[0].length; i++){
			for(int j=0; j<dt.length; j++){
				if((i==lit_y) && (j==lit_x)) System.out.print("X");
				else if(dt[j][i]) System.out.print("O");
				else System.out.print(".");
			}
			System.out.println();
		}
	}
	static void show_L2(long[][] dt, String cmnt){
		PrintWriter out = new PrintWriter(System.out);
		for(int i=0; i<dt[0].length; i++){
			for(int j=0; j<dt.length; j++){
				out.print(dt[j][i]+",");
			}
			out.println("<-"+cmnt+":"+i);
		}
		out.flush();
	}
	static void disp_que(ArrayDeque<Integer> dt){		//上手くいかなかった時用
		int a=0;
		while(dt.size()>0){
			a=dt.removeLast();
			System.out.print(a);
		}
		System.out.println("\n");
	}
	
	
	private static void nextPerm(ArrayList<Integer> former){
		int pivot=-1;
		int ln = former.size();
		for(int i = ln; i>1; i--){
			if(former.get(i-2) < former.get(i-1)){
				pivot = i-2;
				break;
			}
		}
		if(pivot==-1){
		former = null;
		return;
		}
		int pivot_fig = former.get(pivot);
		
		int min_pos=pivot+1;
		int min=former.get(min_pos);
		for(int i=ln-1; i > pivot+1; i--){
			if((former.get(i) < min)&&(former.get(i) > pivot_fig)){
				min_pos=i;
				min=former.get(min_pos);
			}
		}
		Collections.swap(former, pivot, min_pos);
		Collections.sort(former.subList(pivot+1, ln));
		return;
	}
	
	public static int binarySearch(int[] dt, int target){
		int left=0, right=dt.length-1;
		int mid=-1;
		while(left<=right){
			mid = (right+left)/2;
			if(dt[mid] == target) return mid;
			if(dt[mid] < target) left=mid+1;
			else right=mid-1;
		}
		return -1;
	}
	public static int binarySearchMax(long[] dt, long target){
		int left=-1, right=dt.length;
		int mid=-1;
		
		while((right-left)>1){
			mid = left + (right-left)/2;
			if(dt[mid] < target) left=mid;
			else right=mid;
		}
		return left;//target未満の最大のaddress
	}
	
	
	private static int dfs2(boolean[][] state, int x, int y, int depth){		//薄氷渡り
		int[] tmpltX = {1,-1,0,0};
		int[] tmpltY = {0,0,1,-1};
		int newX = -1, newY = -1;
		
		state[x][y] = false;
		depth++;
		
		int maxDunder_this_brunch = depth, tmpD=0;
		for(int i=0; i < 4; i++){
			newX = x+tmpltX[i];
			newY = y+tmpltY[i];
			if((newX >= 0) && (newY >= 0) && (newX < state.length) && (newY < state[0].length) && state[newX][newY]) tmpD = dfs2(state, newX, newY, depth);
			if(tmpD > maxDunder_this_brunch) maxDunder_this_brunch=tmpD;
		}
		state[x][y] = true;
		return maxDunder_this_brunch;
	}
	
    private static int areaSum(int[][] acum_plus1, int bY_notInclude, int aY_include, int bX_notInclude, int aX_include){
        int ans = acum_plus1[aY_include+1][aX_include+1];
        ans -= acum_plus1[aY_include+1][bX_notInclude+1];
        ans -= acum_plus1[bY_notInclude+1][aX_include+1];
        ans += acum_plus1[bY_notInclude+1][bX_notInclude+1];
        return ans;
    }



static class Edge{
    int v2;
    long weight;
    public Edge(int vn, long w){
        this.v2 = vn;
        this.weight = w;
    }
}
static class Edge2{
    int v2;
    long cost1,cost2;
    public Edge2(int vn, long w1, long w2){
        this.v2 = vn;
        this.cost1 = w1;
        this.cost2 = w2;
    }
}

static class Comparator_Edge implements Comparator<Edge>{
    public int compare(Edge a, Edge b){
        if(a.weight>b.weight){
            return 1;
        }else if(a.weight<b.weight){
            return -1;
        }
        return 0;
    }
}
static class FastScanner {
	private final InputStream in = System.in;
	private final byte[] buffer = new byte[1024];
	private int ptr = 0;
	private int buflen = 0;
	private boolean hasNextByte() {
		if (ptr < buflen) {
			return true;
		}else{
			ptr = 0;
			try {
				buflen = in.read(buffer);
			} catch (IOException e) {
				e.printStackTrace();
			}
			if (buflen <= 0) {
				return false;
			}
		}
		return true;
	}
	
	private int readByte() { if (hasNextByte()) return buffer[ptr++]; else return -1;}
	private static boolean isPrintableChar(int c) { return 33 <= c && c <= 126;}
	public boolean hasNext() { while(hasNextByte() && !isPrintableChar(buffer[ptr])) ptr++; return hasNextByte();}
	public String next() {
		if (!hasNext()) throw new NoSuchElementException();
		StringBuilder sb = new StringBuilder();
		int b = readByte();
		while(isPrintableChar(b)) {
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}
	public long nextLong() {
		if (!hasNext()) throw new NoSuchElementException();
		long n = 0;
		boolean minus = false;
		int b = readByte();
		if (b == '-') {
			minus = true;
			b = readByte();
		}
		if (b < '0' || '9' < b) {
			throw new NumberFormatException();
		}
		while(true){
			if ('0' <= b && b <= '9') {
				n *= 10;
				n += b - '0';
			}else if(b == -1 || !isPrintableChar(b)){
				return minus ? -n : n;
			}else{
				throw new NumberFormatException();
			}
			b = readByte();
		}
	}
	public int nextInt() {
		long nl = nextLong();
		if (nl < Integer.MIN_VALUE || nl > Integer.MAX_VALUE) throw new NumberFormatException();
		return (int) nl;
	}
	public double nextDouble() { return Double.parseDouble(next());}
}
}