Problem:
World Trip
Kita_masa is planning a trip around the world.
This world has
N
countries and the country
i
has
M_i
cities.
Kita_masa wants to visit every city exactly once, and return back to the starting city.
In this world, people can travel only by airplane.
There are two kinds of airlines: domestic and international lines.
Since international airports require special facilities such as customs and passport control,
only a few cities in each country have international airports.
You are given a list of all flight routes in this world and prices for each route.
Now it's time to calculate the cheapest route for Kita_masa's world trip!
Input
The first line contains two integers
N
and
K
, which represent the number of countries and the number of flight routes, respectively.
The second line contains
N
integers, and the
i
-th integer
M_i
represents the number of cities in the country
i
.
The third line contains
N
integers too, and the
i
-th integer
F_i
represents the number of international airports in the country
i
.
Each of the following
K
lines contains five integers [Country 1] [City 1] [Country 2] [City 2] [Price].
This means that, there is a bi-directional flight route between the [City 1] in [Country 1] and the [City 2] in [Country 2], and its price is [Price].
Note that cities in each country are numbered from 1, and the cities whose city number is smaller or equal to
F_i
have international airports.
That is, if there is a flight route between the city
c_1
in the country
n_1
and the city
c_2
in the country
n_2
with
n_1 \neq n_2
, it must be
c_1 \leq F_{n_1}
and
c_2 \leq F_{n_2}
.
You can assume that there's no flight route which departs from one city and flies back to the same city, and that at most one flight route exists in this world for each pair of cities.
The following constraints hold for each dataset:
1 \leq N \leq 15
1 \leq M_i \leq 15
1 \leq F_i \leq 4
sum(F_i) \leq 15
1 \leq Price \leq 10,000
Output
Print a line that contains a single integer representing the minimum price to make a world trip.
If such a trip is impossible, print -1 instead.
Sample Input 1
4 6
1 1 1 1
1 1 1 1
1 1 2 1 1
1 1 3 1 2
1 1 4 1 1
2 1 3 1 1
2 1 4 1 2
3 1 4 1 1
Output for the Sample Input 1
4
Sample Input 2
2 16
4 4
2 2
1 1 1 2 1
1 1 1 3 2
1 1 1 4 1
1 2 1 3 1
1 2 1 4 2
1 3 1 4 1
2 1 2 2 1
2 1 2 3 2
2 1 2 4 1
2 2 2 3 1
2 2 2 4 2
2 3 2 4 1
1 1 2 1 1
1 1 2 2 2
1 2 2 1 2
1 2 2 2 1
Output for the Sample Input 2
8
Sample Input 3
2 2
2 1
1 1
1 1 1 2 1
1 1 2 1 1
Output for the Sample Input 3
-1

Submitted solutions:

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 15
#define NUM 32768

struct Edge{
	Edge(int arg_to_country,int arg_to_city,int arg_cost){
		to_country = arg_to_country;
		to_city = arg_to_city;
		cost = arg_cost;
	}
	int to_country,to_city,cost;
};

struct INPUT{
	bool operator<(const struct INPUT &arg) const{

		if(OUTER != arg.OUTER){
			return OUTER > arg.OUTER;
		}else{
			return CITY > arg.CITY;
		}
	}
	int index,CITY,OUTER;
};

struct Edge2{
	Edge2(int arg_to,int arg_cost){
		to = arg_to;
		cost = arg_cost;
	}
	int to,cost;
};

struct Info{
	Info(int arg_num_out,int arg_IN[4],int arg_OUT[4],int arg_COST[3],int arg_COUNT,int arg_num_L,int arg_L[3]){
		num_out = arg_num_out;
		for(int i = 0; i < num_out; i++){
			IN[i] = arg_IN[i];
			OUT[i] = arg_OUT[i];
		}
		for(int i = 0; i < 3; i++){

			COST[i] = arg_COST[i];
			L[i] = arg_L[i];
		}
		num_L = arg_num_L;
		COUNT = arg_COUNT;
	}
	int num_out,IN[4],OUT[4],COST[3],num_L,L[3],COUNT;
};

struct Data{
	void set(int arg_country,int arg_left,int arg_right){
		country = arg_country;
		left = arg_left;
		right = arg_right;
	}
	int country;
	int left,right;
};

struct DEBUG{

	int pre_state,pre_node;
};

int N,K;
int num_city[SIZE],num_outer[SIZE];
int POW[SIZE+1];
int STATE[SIZE];
int ONE[NUM][SIZE];
int DIST[SIZE][SIZE][SIZE][SIZE];
int work_dp[SIZE][NUM][SIZE];
int DP[NUM][SIZE];
int ans;
int num_STATE[SIZE+1];
int table[SIZE+1][NUM];
int LAST[SIZE+1][NUM][SIZE+1],num_LAST[SIZE+1][NUM];
int NEXT[SIZE+1][NUM][SIZE+1][SIZE+1];
int num_NEXT[SIZE+1][NUM][SIZE+1];
int NOT[NUM][SIZE+1],num_NOT[NUM];
int work_DIST[SIZE][SIZE],calc_DIST[SIZE][SIZE][SIZE];
bool used[SIZE][4][4][4][4],pair_used[SIZE][4][4];
Data DATA[SIZE];
vector<Edge> same_G[SIZE][SIZE],diff_G[SIZE][SIZE];
vector<Info> info[SIZE];
map<int,int> MAP;
INPUT input[SIZE+1];


void calc_2(int index){

	if(num_city[index] == 2){ //立ち寄り2回

		int IN[4] = {0,1,-1,-1};
		int OUT[4] = {0,1,-1,-1};
		int COST[3] = {0,-1,-1};
		int L[3];

		info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));

	}else{ //?入りsecond出

		if(index == 0){

			int work[num_outer[index]];
			for(int i = 0; i < num_outer[index]; i++){

				work[i] = i;
			}

			do{

				int first = work[0];
				int second = work[1];
				if(first > second)continue; //★★left-rigithが全て真逆のパターンの発生を防ぐ(結果が同じになる)★★
				if(work_dp[first][POW[num_city[0]]-1][second] == BIG_NUM)continue;

				int IN[3] = {first,-1,-1};
				int OUT[3] = {second,-1,-1};
				int COST[3] = {work_dp[first][POW[num_city[0]]-1][second],-1,-1};
				int L[3];

				info[0].push_back(Info(1,IN,OUT,COST,-1,0,L));

			}while(next_permutation(work,work+num_outer[index]));

			return;
		}

		for(int second = 0; second < num_outer[index]; second++){
			int num_L = 0;
			int IN[3] = {-1,-1,-1};
			int OUT[3] = {second,-1,-1};
			int COST[3] = {-1,-1,-1};
			int L[3];

			for(int first = 0; first < num_outer[index]; first++){
				if(first == second)continue;
				if(work_dp[first][POW[num_city[index]]-1][second] == BIG_NUM)continue;

				COST[num_L] = work_dp[first][POW[num_city[index]]-1][second];
				L[num_L++] = first;
			}
			if(num_L == 0)continue;
			if(num_L == 1){
				IN[0] = L[0];
				info[index].push_back(Info(1,IN,OUT,COST,-1,0,L));
			}else{
				info[index].push_back(Info(1,IN,OUT,COST,2,num_L,L));
			}
		}
	}
}

void calc_3(int index){

	if(num_outer[index] == 3){

		if(num_city[index] == 3){ //立ち寄り3回

			int IN[4] = {0,1,2,-1};
			int OUT[4] = {0,1,2,-1};
			int COST[3] = {0,-1,-1};
			int L[3];

			info[index].push_back(Info(3,IN,OUT,COST,-1,0,L));

		}else{ //first立ち寄り,second入りthird出

			int work[4] = {0,1,2,3};

			do{
				int first = work[0];
				int second = work[1];
				int third = work[2];

				int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

				if(work_dp[second][to_state][third] < BIG_NUM){

					int IN[4] = {first,second,-1,-1};
					int OUT[4] = {first,third,-1,-1};
					int COST[3] = {work_dp[second][to_state][third],-1,-1};
					int L[3];

					info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));
				}

			}while(next_permutation(work,work+3));
		}
	}else{ //num_outer[index] == 4

		//★★first立ち寄り,?入りthird出★★
		for(int first = 0; first < 4; first++){
			for(int third = 0; third < 4; third++){
				if(third == first)continue;

				int IN[4] = {first,-1,-1,-1};
				int OUT[4] = {first,third,-1,-1};
				int COST[3] = {-1,-1,-1};
				int L[3] = {-1,-1,-1};

				int num_L = 0;

				for(int second = 0; second < 4; second++){
					if(second == first || second == third || (index == 0 && second >third))continue;

					int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

					if(work_dp[second][to_state][third] < BIG_NUM){

						COST[num_L] = work_dp[second][to_state][third];
						L[num_L++] = second;
					}
				}
				if(num_L == 0)continue;
				if(num_L == 1){

					IN[1] = L[0];
					info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));
				}else{

					info[index].push_back(Info(2,IN,OUT,COST,3,num_L,L));
				}
			}
		}
	}
}

void calc_4(int index,int work[4]){

	int L[3];

	if(num_city[index] == 4){ //立ち寄り4回

		int IN[4] = {work[0],work[1],work[2],work[3]};
		int OUT[4] = {work[0],work[1],work[2],work[3]};
		int COST[3] = {0,-1,-1};

		info[index].push_back(Info(4,IN,OUT,COST,-1,0,L));

	}else{

		do{

			int a = work[0];
			int b = work[1];
			int c = work[2];
			int d = work[3];

			//a入りb出-c入d出
			if(!used[index][c][d][a][b]){
				used[index][a][b][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[c]+POW[d]);
				int tmp_cost = BIG_NUM;

				for(int from_state = 1; from_state <= to_state; from_state++){
					if(((from_state & POW[c]) == POW[c]) ||
						((from_state & POW[d]) == POW[d]) ||
						((from_state & POW[a]) != POW[a]) ||
						((from_state & POW[b]) != POW[b]))continue;
					if(work_dp[a][from_state][b] == BIG_NUM)continue;

					int rest_state = POW[num_city[index]]-1-from_state;
					if(work_dp[c][rest_state][d] == BIG_NUM)continue;

					tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
				}

				if(tmp_cost < BIG_NUM){

					int IN[4] = {a,c,-1,-1};
					int OUT[4] = {b,d,-1,-1};
					int COST[3] = {tmp_cost,-1,-1};

					info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));
				}
			}

			//a,b立ち寄り,c入d出
			if(!pair_used[index][c][d]){
				pair_used[index][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[a]+POW[b]);

				if(work_dp[c][to_state][d] < BIG_NUM){

					int IN[4] = {a,b,c,-1};
					int OUT[4] = {a,b,d,-1};
					int COST[3] = {work_dp[c][to_state][d],-1,-1};

					info[index].push_back(Info(3,IN,OUT,COST,-1,0,L));
				}
			}

		}while(next_permutation(work,work+4));
	}
}

void calc_zero(int count_outer){

	int L[3];

	for(int left = 0; left <= 2; left++){
		int IN[4] = {left,-1,-1,-1};
		int OUT[4] = {-1,-1,-1,-1};

		int COST[3];
		for(int i = 0; i < 3; i++){

			COST[i] = -1;
		}
		for(int right = left+1; right <= 3; right++){

			COST[right-(left+1)] = work_dp[left][POW[num_city[0]]-1][right]; //left入りright出
		}

		info[0].push_back(Info(1,IN,OUT,COST,2,0,L));
	}

	int first,second,third;

	int work[4] = {0,1,2,3};

	do{
		first = work[0];
		second = work[1];
		third = work[2];
		if(second > third)continue;

		int to_state = (POW[num_city[0]]-1)-POW[first]; //firstを除いてTSP

		if(work_dp[second][to_state][third] < BIG_NUM){

			int IN[4] = {first,second,-1,-1};
			int OUT[4] = {first,third,-1,-1};
			int COST[3] = {work_dp[second][to_state][third],-1,-1};

			info[0].push_back(Info(2,IN,OUT,COST,-1,0,L));
		}

	}while(next_permutation(work,work+4));

	int a,b,c,d;
	for(int loop = 0; loop < 6; loop++){
		if(loop == 0){
			a = 0;
			b = 1;
			c = 2;
			d = 3;
		}else if(loop == 1){
			a = 0;
			b = 1;
			c = 3;
			d = 2;
		}else if(loop == 2){
			a = 0;
			b = 2;
			c = 1;
			d = 3;
		}else if(loop == 3){
			a = 0;
			b = 2;
			c = 3;
			d = 1;
		}else if(loop == 4){
			a = 0;
			b = 3;
			c = 1;
			d = 2;
		}else{ //loop == 5
			a = 0;
			b = 3;
			c = 2;
			d = 1;
		}

		//a入りb出-c入d出
		int to_state = (POW[num_city[0]]-1)-(POW[c]+POW[d]);
		int tmp_cost = BIG_NUM;

		for(int from_state = 1; from_state <= to_state; from_state++){
			if(((from_state & POW[c]) == POW[c]) ||
				((from_state & POW[d]) == POW[d]) ||
				((from_state & POW[a]) != POW[a]) ||
				((from_state & POW[b]) != POW[b]))continue;
			if(work_dp[a][from_state][b] == BIG_NUM)continue;

			int rest_state = POW[num_city[0]]-1-from_state;
			if(work_dp[c][rest_state][d] == BIG_NUM)continue;

			tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
		}

		if(tmp_cost < BIG_NUM){

			int IN[4] = {a,c,-1,-1};
			int OUT[4] = {b,d,-1,-1};
			int COST[3] = {tmp_cost,-1,-1};

			info[0].push_back(Info(2,IN,OUT,COST,-1,0,L));
		}
	}

	for(int loop = 0; loop < 6; loop++){
		if(loop == 0){
			a = 2;
			b = 3;
			c = 0;
			d = 1;
		}else if(loop == 1){
			a = 1;
			b = 3;
			c = 0;
			d = 2;
		}else if(loop == 2){
			a = 1;
			b = 2;
			c = 0;
			d = 3;
		}else if(loop == 3){
			a = 0;
			b = 3;
			c = 1;
			d = 2;
		}else if(loop == 4){
			a = 0;
			b = 2;
			c = 1;
			d = 3;
		}else{ //loop == 5
			a = 0;
			b = 1;
			c = 2;
			d = 3;
		}

		//a,b立ち寄り,c入d出
		int to_state = (POW[num_city[0]]-1)-(POW[a]+POW[b]);

		if(work_dp[c][to_state][d] < BIG_NUM){

			int IN[4] = {a,b,c,-1};
			int OUT[4] = {a,b,d,-1};
			int COST[3] = {work_dp[c][to_state][d],-1,-1};
			info[0].push_back(Info(3,IN,OUT,COST,-1,0,L));
		}
	}
}

void calc_one(){

	if(num_city[0] == 1){

		printf("0\n");
		return;
	}

	int index = 0;

	for(int state = 0; state < POW[num_city[index]]; state++){
		for(int last = 0; last < num_city[index]; last++){

			ONE[state][last] = BIG_NUM;
		}
	}

	//経路は輪になるので、スタートは0として良いはず
	ONE[POW[0]][0] = 0;

	for(int state = 1; state < POW[num_city[index]]-1; state++){
		for(int last = 0; last < num_city[index]; last++){
			if(ONE[state][last] == BIG_NUM)continue;

			for(int i = 0; i < same_G[index][last].size(); i++){

				int next_node = same_G[index][last][i].to_city;

				if(state & POW[next_node])continue;

				int next_state = state+POW[next_node];
				int next_cost = ONE[state][last]+same_G[index][last][i].cost;

				ONE[next_state][next_node] = min(ONE[next_state][next_node],next_cost);
			}
		}
	}

	int ans = BIG_NUM;
	for(int last = 0; last < num_city[index]; last++){
		if(ONE[POW[num_city[index]]-1][last] == BIG_NUM)continue;

		ans = min(ans,ONE[POW[num_city[index]]-1][last]+DIST[0][last][0][0]);
	}

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}
}
void recursive(int index){

	if(index < N){

		for(int i = 0; i < info[index].size(); i++){

			STATE[index] = i;
			recursive(index+1);
		}
		return;
	}

	//index == N
	int num_DATA = 0;
	int add = 0;

	for(int i = 0; i < N; i++){
		int num = STATE[i];
		if(info[i][num].COUNT == -1){
			add += info[i][num].COST[0];
		}
		for(int k = 0; k < info[i][num].num_out; k++){

			DATA[num_DATA++].set(i,info[i][num].IN[k],info[i][STATE[i]].OUT[k]);
		}
	}

	if(add >= ans)return;

	for(int i = 0; i < num_DATA; i++){
		for(int k = 0; k < num_DATA; k++){

			work_DIST[i][k] = BIG_NUM;
		}
	}

	for(int i = 1; i < num_DATA; i++){
		for(int k = 1; k < num_DATA; k++){
			if((k == i)||(num_city[DATA[i].country] < num_outer[DATA[i].country] && DATA[i].country == DATA[k].country))continue;

			int from_country = DATA[i].country;
			int from_city = DATA[i].right;

			if(DATA[k].left == -1){

				for(int a = 0; a < 4; a++){

					calc_DIST[i][k][a] = BIG_NUM;
				}

				int to_country = DATA[k].country;

				for(int a = 0; a < info[to_country][STATE[to_country]].num_L; a++){

					int to_city = info[to_country][STATE[to_country]].L[a];
					calc_DIST[i][k][a] = DIST[from_country][from_city][to_country][to_city];
				}

				continue;
			}

			int to_country = DATA[k].country;
			int to_city = DATA[k].left;

			if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

			work_DIST[i][k] = DIST[from_country][from_city][to_country][to_city];
		}
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		int state = table[num_DATA][i];
		for(int k = 0; k < num_LAST[num_DATA][state]; k++){

			DP[state][LAST[num_DATA][state][k]] = BIG_NUM;
		}
	}
	for(int last = 1; last < num_DATA; last++){

		DP[POW[num_DATA]-1][last] = BIG_NUM;
	}

	for(int k = 1; k < num_DATA; k++){
		if(info[0][STATE[0]].COUNT == -1){ //国0がnum2でない
				int from_country = 0;
				int from_city = DATA[0].right;

				if(DATA[k].left != -1){

					int to_country = DATA[k].country;
					int to_city = DATA[k].left;

					if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

					DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],DIST[from_country][from_city][to_country][to_city]);
				}else{

					int to_country = DATA[k].country;
					for(int a = 0; a < info[to_country][STATE[to_country]].num_L; a++){

						int to_city = info[to_country][STATE[to_country]].L[a];

						if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

						DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],
								DIST[from_country][from_city][to_country][to_city]+info[to_country][STATE[to_country]].COST[a]);
					}
				}

		}else{ //国0がnum2

			int left = DATA[0].left;

			for(int right = left+1; right <= 3; right++){

				int from_country = 0;
				int from_city = right;

				if(DATA[k].left != -1){

					int to_country = DATA[k].country;
					int to_city = DATA[k].left;

					if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;
					int tmp_cost = info[0][STATE[0]].COST[right-(left+1)];
					if(tmp_cost == BIG_NUM)continue;

					DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],DIST[from_country][from_city][to_country][to_city]+tmp_cost);
				}else{

					int tmp_cost = info[0][STATE[0]].COST[right-(left+1)];
					if(tmp_cost == BIG_NUM)continue;

					int to_country = DATA[k].country;
					for(int a = 0; a < info[to_country][STATE[to_country]].num_L; a++){

						int to_city = info[to_country][STATE[to_country]].L[a];
						if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

						DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],
								DIST[from_country][from_city][to_country][to_city]+info[to_country][STATE[to_country]].COST[a]+tmp_cost);
					}
				}
			}
		}
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		int state = table[num_DATA][i];
		int max_k = num_LAST[num_DATA][state];
		for(int k = 0; k < max_k; k++){
			int last = LAST[num_DATA][state][k];
			if(DP[state][last]==BIG_NUM)continue;
			int max_a = num_NEXT[num_DATA][state][k];
			for(int a = 0; a < max_a; a++){
				int next = NEXT[num_DATA][state][k][a];
				if(DATA[next].left != -1){
					DP[state|(1<<next)][next] = min(DP[state|(1<<next)][next],DP[state][last]+work_DIST[last][next]);
				}else{

					int to_country = DATA[next].country;
					int max_b = info[to_country][STATE[to_country]].num_L;

					for(int b = 0; b < max_b; b++){
						if(calc_DIST[last][next][b] == BIG_NUM)continue;

						DP[state|(1<<next)][next] = min(DP[state|(1<<next)][next],
								DP[state][last]+calc_DIST[last][next][b]+info[to_country][STATE[to_country]].COST[b]);
					}
				}
			}
		}
	}

	int tmp_ans = BIG_NUM;

	for(int last = 1; last < num_DATA; last++){
		if(DP[POW[num_DATA]-1][last] == BIG_NUM)continue;

		int pre_country = DATA[last].country;
		int pre_city = DATA[last].right;

		int next_country = DATA[0].country;
		int next_city = DATA[0].left;

		if(DIST[pre_country][pre_city][next_country][next_city] == BIG_NUM)continue;

		if(tmp_ans > DP[POW[num_DATA]-1][last]+
				DIST[pre_country][pre_city][next_country][next_city]){
			tmp_ans = DP[POW[num_DATA]-1][last]+
					DIST[pre_country][pre_city][next_country][next_city];
		}
	}

	if(tmp_ans < BIG_NUM){

		ans = min(ans,tmp_ans+add);
	}
}

void calc_dp(int index){

	for(int start = 0; start < num_outer[index]; start++){
		for(int state = 0; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){

				work_dp[start][state][last] = BIG_NUM;
			}
		}
	}

	for(int i = 0; i < num_outer[index]; i++){
		work_dp[i][POW[i]][i] = 0;
		for(int state = 1; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){
				if(work_dp[i][state][last] == BIG_NUM)continue;

				for(int next = 0; next < num_city[index]; next++){
					if(state & POW[next])continue;
					if(DIST[index][last][index][next] == BIG_NUM)continue;

					int next_state = state+POW[next];
					int next_cost = work_dp[i][state][last]+DIST[index][last][index][next];

					work_dp[i][next_state][next] = min(work_dp[i][next_state][next],next_cost);
				}
			}
		}
	}
}

void calc_LAST_NEXT(){

	for(int i = 2; i <= 15; i++){
		int maximum = POW[i];
		num_STATE[i] = 0;
		for(int state = 3; state <= maximum-3; state += 2){ //DATA[0]を訪問済の状態のみ列挙

			table[i][num_STATE[i]++] = state;

			num_NOT[state] = 0;
			for(int k = 1; k < i; k++){
				if(state&POW[k])continue;
				NOT[state][num_NOT[state]++] = k;
			}

			num_LAST[i][state] = 0;

			for(int last = 1; last < i; last++){ //訪問済のノードを前計算
				if((state&POW[last]) == 0)continue;

				LAST[i][state][num_LAST[i][state]] = last;
				num_NEXT[i][state][num_LAST[i][state]] = 0;

				for(int next = 1; next < i; next++){ //未訪問のノードを前計算
					if(next == last)continue;
					if(state&POW[next])continue;

					NEXT[i][state][num_LAST[i][state]][num_NEXT[i][state][num_LAST[i][state]]++] = next;
				}
				num_LAST[i][state]++;
			}
		}
	}
}

int main(){

	POW[0] = 1;
	for(int i = 1; i <= SIZE; i++){

		POW[i] = POW[i-1]*2;
	}

	for(int a = 0; a < SIZE; a++){
		for(int b = 0; b < SIZE; b++){
			for(int c = 0; c < SIZE; c++){
				for(int d = 0; d < SIZE; d++){
					DIST[a][b][c][d] = BIG_NUM;
				}
			}
		}
	}

	for(int i = 0; i < SIZE; i++){
		for(int a = 0; a < 4; a++){
			for(int b = 0; b < 4; b++){
				pair_used[i][a][b] = false;
				for(int c = 0; c < 4; c++){
					for(int d = 0; d < 4; d++){
						used[i][a][b][c][d] = false;
					}
				}
			}
		}
	}

	scanf("%d %d",&N,&K);

	for(int i = 0; i < N; i++){
		input[i].index = i;
		scanf("%d",&input[i].CITY);
	}

	for(int i = 0; i < N; i++){

		scanf("%d",&input[i].OUTER);
	}

	sort(input,input+N);

	for(int i = 0; i < N; i++){
		MAP[input[i].index] = i;
		num_city[i] = input[i].CITY;
		num_outer[i] = input[i].OUTER;
	}

	int from_country,from_city,to_country,to_city,cost;

	for(int i = 0; i < K; i++){

		scanf("%d %d %d %d %d",&from_country,&from_city,&to_country,&to_city,&cost);
		from_country--;
		from_city--;
		to_country--;
		to_city--;

		from_country = MAP[from_country];
		to_country = MAP[to_country];

		if(from_country == to_country){

			same_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			same_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));

		}else{

			diff_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			diff_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));
		}

		DIST[from_country][from_city][to_country][to_city] = cost;
		DIST[to_country][to_city][from_country][from_city] = cost;
	}

	if(N == 1){

		calc_one();
		return 0;
	}

	calc_LAST_NEXT();
	int start = 0;

	if(num_outer[0] == 4 && num_city[0] > 4){
		calc_dp(0);
		start = 1;
		calc_zero(num_outer[0]);
	}

	for(int i = start; i < N; i++){

		if(num_outer[i] == 1){

			int IN[4] = {0,-1,-1,-1};
			int OUT[4] = {0,-1,-1,-1};
			int COST[3] = {0,-1,-1};
			int L[3];

			if(num_city[i] > 1){

				printf("-1\n");
				return 0;

			}else{

				info[i].push_back(Info(1,IN,OUT,COST,-1,0,L));
			}

		}else if(num_outer[i] == 2){

			calc_dp(i);
			calc_2(i);

		}else if(num_outer[i] == 3){

			calc_dp(i);

			calc_2(i);
			calc_3(i);


		}else{ //num_outer[i] == 4

			calc_dp(i);

			if(num_city[i] > 4){
				calc_2(i);
				calc_3(i);
			}
			int work_4[4];
			for(int a = 0; a < 4; a++){

				work_4[a] = a;
			}
			calc_4(i,work_4);
		}
	}

	for(int i = 0; i < N; i++){
		if(info[i].size() == 0){

			printf("-1\n");
			return 0;
		}
	}

	ans = BIG_NUM;
	recursive(0);

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}

	return 0;
}
accuracy: 1
time_ms: 4610
memory_kb: 87688
final_rank: 1

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 15
#define NUM 32768

struct Edge{
	Edge(int arg_to_country,int arg_to_city,int arg_cost){
		to_country = arg_to_country;
		to_city = arg_to_city;
		cost = arg_cost;
	}
	int to_country,to_city,cost;
};

struct INPUT{
	bool operator<(const struct INPUT &arg) const{

		if(OUTER != arg.OUTER){
			return OUTER > arg.OUTER;
		}else{
			return CITY > arg.CITY;
		}
	}
	int index,CITY,OUTER;
};

struct Edge2{
	Edge2(int arg_to,int arg_cost){
		to = arg_to;
		cost = arg_cost;
	}
	int to,cost;
};

struct Info{
	Info(int arg_num_out,int arg_IN[4],int arg_OUT[4],int arg_COST[3],int arg_COUNT,int arg_num_L,int arg_L[3]){
		num_out = arg_num_out;
		for(int i = 0; i < num_out; i++){
			IN[i] = arg_IN[i];
			OUT[i] = arg_OUT[i];
		}
		for(int i = 0; i < 3; i++){

			COST[i] = arg_COST[i];
			L[i] = arg_L[i];
		}
		num_L = arg_num_L;
		COUNT = arg_COUNT;
	}
	int num_out,IN[4],OUT[4],COST[3],num_L,L[3],COUNT;
};

struct Data{
	void set(int arg_country,int arg_left,int arg_right){
		country = arg_country;
		left = arg_left;
		right = arg_right;
	}
	int country;
	int left,right;
};

struct DEBUG{

	int pre_state,pre_node;
};

int N,K;
int num_city[SIZE],num_outer[SIZE];
int POW[SIZE+1];
int STATE[SIZE];
int ONE[NUM][SIZE];
int DIST[SIZE][SIZE][SIZE][SIZE];
int work_dp[SIZE][NUM][SIZE];
int DP[NUM][SIZE];
int ans;
int num_STATE[SIZE+1];
int table[SIZE+1][NUM];
int LAST[SIZE+1][NUM][SIZE+1],num_LAST[SIZE+1][NUM];
int NEXT[SIZE+1][NUM][SIZE+1][SIZE+1];
int num_NEXT[SIZE+1][NUM][SIZE+1];
int NOT[NUM][SIZE+1],num_NOT[NUM];
int work_DIST[SIZE][SIZE],calc_DIST[SIZE][SIZE][SIZE];
bool used[SIZE][4][4][4][4],pair_used[SIZE][4][4];
Data DATA[SIZE];
vector<Edge> same_G[SIZE][SIZE],diff_G[SIZE][SIZE];
vector<Info> info[SIZE];
map<int,int> MAP;
INPUT input[SIZE+1];


void calc_2(int index){

	if(num_city[index] == 2){ //立ち寄り2回

		int IN[4] = {0,1,-1,-1};
		int OUT[4] = {0,1,-1,-1};
		int COST[3] = {0,-1,-1};
		int L[3];

		info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));

	}else{ //?入りsecond出

		if(index == 0){

			int work[num_outer[index]];
			for(int i = 0; i < num_outer[index]; i++){

				work[i] = i;
			}

			do{

				int first = work[0];
				int second = work[1];
				if(first > second)continue;
				if(work_dp[first][POW[num_city[0]]-1][second] == BIG_NUM)continue;

				int IN[3] = {first,-1,-1};
				int OUT[3] = {second,-1,-1};
				int COST[3] = {work_dp[first][POW[num_city[0]]-1][second],-1,-1};
				int L[3];

				info[0].push_back(Info(1,IN,OUT,COST,-1,0,L));

			}while(next_permutation(work,work+num_outer[index]));

			return;
		}

		for(int second = 0; second < num_outer[index]; second++){
			int num_L = 0;
			int IN[3] = {-1,-1,-1};
			int OUT[3] = {second,-1,-1};
			int COST[3] = {-1,-1,-1};
			int L[3];

			for(int first = 0; first < num_outer[index]; first++){
				if(first == second)continue;
				if(work_dp[first][POW[num_city[index]]-1][second] == BIG_NUM)continue;

				COST[num_L] = work_dp[first][POW[num_city[index]]-1][second];
				L[num_L++] = first;
			}
			if(num_L == 0)continue;
			if(num_L == 1){
				IN[0] = L[0];
				info[index].push_back(Info(1,IN,OUT,COST,-1,0,L));
			}else{
				info[index].push_back(Info(1,IN,OUT,COST,2,num_L,L));
			}
		}
	}
}

void calc_3(int index){

	if(num_outer[index] == 3){

		if(num_city[index] == 3){ //立ち寄り3回

			int IN[4] = {0,1,2,-1};
			int OUT[4] = {0,1,2,-1};
			int COST[3] = {0,-1,-1};
			int L[3];

			info[index].push_back(Info(3,IN,OUT,COST,-1,0,L));

		}else{ //first立ち寄り,second入りthird出

			int work[4] = {0,1,2,3};

			do{
				int first = work[0];
				int second = work[1];
				int third = work[2];

				int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

				if(work_dp[second][to_state][third] < BIG_NUM){

					int IN[4] = {first,second,-1,-1};
					int OUT[4] = {first,third,-1,-1};
					int COST[3] = {work_dp[second][to_state][third],-1,-1};
					int L[3];

					info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));
				}

			}while(next_permutation(work,work+3));
		}
	}else{ //num_outer[index] == 4

		for(int first = 0; first < 4; first++){
			for(int third = 0; third < 4; third++){
				if(third == first)continue;

				int IN[4] = {first,-1,-1,-1};
				int OUT[4] = {first,third,-1,-1};
				int COST[3] = {-1,-1,-1};
				int L[3] = {-1,-1,-1};

				int num_L = 0;

				for(int second = 0; second < 4; second++){
					if(second == first || second == third || (index == 0 && second >third))continue;

					int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

					if(work_dp[second][to_state][third] < BIG_NUM){

						COST[num_L] = work_dp[second][to_state][third];
						L[num_L++] = second;
					}
				}
				if(num_L == 0)continue;
				if(num_L == 1){

					IN[1] = L[0];
					info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));
				}else{

					info[index].push_back(Info(2,IN,OUT,COST,3,num_L,L));
				}
			}
		}
	}
}

void calc_4(int index,int work[4]){

	int L[3];

	if(num_city[index] == 4){ //立ち寄り4回

		int IN[4] = {work[0],work[1],work[2],work[3]};
		int OUT[4] = {work[0],work[1],work[2],work[3]};
		int COST[3] = {0,-1,-1};

		info[index].push_back(Info(4,IN,OUT,COST,-1,0,L));

	}else{

		do{

			int a = work[0];
			int b = work[1];
			int c = work[2];
			int d = work[3];

			//a入りb出-c入d出
			if(!used[index][c][d][a][b]){
				used[index][a][b][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[c]+POW[d]);
				int tmp_cost = BIG_NUM;

				for(int from_state = 1; from_state <= to_state; from_state++){
					if(((from_state & POW[c]) == POW[c]) ||
						((from_state & POW[d]) == POW[d]) ||
						((from_state & POW[a]) != POW[a]) ||
						((from_state & POW[b]) != POW[b]))continue;
					if(work_dp[a][from_state][b] == BIG_NUM)continue;

					int rest_state = POW[num_city[index]]-1-from_state;
					if(work_dp[c][rest_state][d] == BIG_NUM)continue;

					tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
				}

				if(tmp_cost < BIG_NUM){

					int IN[4] = {a,c,-1,-1};
					int OUT[4] = {b,d,-1,-1};
					int COST[3] = {tmp_cost,-1,-1};

					info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));
				}
			}

			//a,b立ち寄り,c入d出
			if(!pair_used[index][c][d]){
				pair_used[index][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[a]+POW[b]);

				if(work_dp[c][to_state][d] < BIG_NUM){

					int IN[4] = {a,b,c,-1};
					int OUT[4] = {a,b,d,-1};
					int COST[3] = {work_dp[c][to_state][d],-1,-1};

					info[index].push_back(Info(3,IN,OUT,COST,-1,0,L));
				}
			}

		}while(next_permutation(work,work+4));
	}
}

void calc_zero(int count_outer){

	int L[3];

	for(int left = 0; left <= 2; left++){
		int IN[4] = {left,-1,-1,-1};
		int OUT[4] = {-1,-1,-1,-1};

		int COST[3];
		for(int i = 0; i < 3; i++){

			COST[i] = -1;
		}
		for(int right = left+1; right <= 3; right++){

			COST[right-(left+1)] = work_dp[left][POW[num_city[0]]-1][right]; //left入りright出
		}

		info[0].push_back(Info(1,IN,OUT,COST,2,0,L));
	}

	int first,second,third;

	int work[4] = {0,1,2,3};

	do{
		first = work[0];
		second = work[1];
		third = work[2];
		if(second > third)continue;

		int to_state = (POW[num_city[0]]-1)-POW[first]; //firstを除いてTSP

		if(work_dp[second][to_state][third] < BIG_NUM){

			int IN[4] = {first,second,-1,-1};
			int OUT[4] = {first,third,-1,-1};
			int COST[3] = {work_dp[second][to_state][third],-1,-1};

			info[0].push_back(Info(2,IN,OUT,COST,-1,0,L));
		}

	}while(next_permutation(work,work+4));

	int a,b,c,d;
	for(int loop = 0; loop < 6; loop++){
		if(loop == 0){
			a = 0;
			b = 1;
			c = 2;
			d = 3;
		}else if(loop == 1){
			a = 0;
			b = 1;
			c = 3;
			d = 2;
		}else if(loop == 2){
			a = 0;
			b = 2;
			c = 1;
			d = 3;
		}else if(loop == 3){
			a = 0;
			b = 2;
			c = 3;
			d = 1;
		}else if(loop == 4){
			a = 0;
			b = 3;
			c = 1;
			d = 2;
		}else{ //loop == 5
			a = 0;
			b = 3;
			c = 2;
			d = 1;
		}

		//a入りb出-c入d出
		int to_state = (POW[num_city[0]]-1)-(POW[c]+POW[d]);
		int tmp_cost = BIG_NUM;

		for(int from_state = 1; from_state <= to_state; from_state++){
			if(((from_state & POW[c]) == POW[c]) ||
				((from_state & POW[d]) == POW[d]) ||
				((from_state & POW[a]) != POW[a]) ||
				((from_state & POW[b]) != POW[b]))continue;
			if(work_dp[a][from_state][b] == BIG_NUM)continue;

			int rest_state = POW[num_city[0]]-1-from_state;
			if(work_dp[c][rest_state][d] == BIG_NUM)continue;

			tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
		}

		if(tmp_cost < BIG_NUM){

			int IN[4] = {a,c,-1,-1};
			int OUT[4] = {b,d,-1,-1};
			int COST[3] = {tmp_cost,-1,-1};

			info[0].push_back(Info(2,IN,OUT,COST,-1,0,L));
		}
	}

	for(int loop = 0; loop < 6; loop++){
		if(loop == 0){
			a = 2;
			b = 3;
			c = 0;
			d = 1;
		}else if(loop == 1){
			a = 1;
			b = 3;
			c = 0;
			d = 2;
		}else if(loop == 2){
			a = 1;
			b = 2;
			c = 0;
			d = 3;
		}else if(loop == 3){
			a = 0;
			b = 3;
			c = 1;
			d = 2;
		}else if(loop == 4){
			a = 0;
			b = 2;
			c = 1;
			d = 3;
		}else{ //loop == 5
			a = 0;
			b = 1;
			c = 2;
			d = 3;
		}

		//a,b立ち寄り,c入d出
		int to_state = (POW[num_city[0]]-1)-(POW[a]+POW[b]);

		if(work_dp[c][to_state][d] < BIG_NUM){

			int IN[4] = {a,b,c,-1};
			int OUT[4] = {a,b,d,-1};
			int COST[3] = {work_dp[c][to_state][d],-1,-1};
			info[0].push_back(Info(3,IN,OUT,COST,-1,0,L));
		}
	}
}

void calc_one(){

	if(num_city[0] == 1){

		printf("0\n");
		return;
	}

	int index = 0;

	for(int state = 0; state < POW[num_city[index]]; state++){
		for(int last = 0; last < num_city[index]; last++){

			ONE[state][last] = BIG_NUM;
		}
	}

	//経路は輪になるので、スタートは0として良いはず
	ONE[POW[0]][0] = 0;

	for(int state = 1; state < POW[num_city[index]]-1; state++){
		for(int last = 0; last < num_city[index]; last++){
			if(ONE[state][last] == BIG_NUM)continue;

			for(int i = 0; i < same_G[index][last].size(); i++){

				int next_node = same_G[index][last][i].to_city;

				if(state & POW[next_node])continue;

				int next_state = state+POW[next_node];
				int next_cost = ONE[state][last]+same_G[index][last][i].cost;

				ONE[next_state][next_node] = min(ONE[next_state][next_node],next_cost);
			}
		}
	}

	int ans = BIG_NUM;
	for(int last = 0; last < num_city[index]; last++){
		if(ONE[POW[num_city[index]]-1][last] == BIG_NUM)continue;

		ans = min(ans,ONE[POW[num_city[index]]-1][last]+DIST[0][last][0][0]);
	}

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}
}
void recursive(int index){

	if(index < N){

		for(int i = 0; i < info[index].size(); i++){

			STATE[index] = i;
			recursive(index+1);
		}
		return;
	}

	//index == N
	int num_DATA = 0;
	int add = 0;




	for(int i = 0; i < N; i++){
		int num = STATE[i];
		if(info[i][num].COUNT == -1){
			add += info[i][num].COST[0];
		}
		for(int k = 0; k < info[i][num].num_out; k++){

			DATA[num_DATA++].set(i,info[i][num].IN[k],info[i][STATE[i]].OUT[k]);
		}
	}

	if(add >= ans)return;

	for(int i = 0; i < num_DATA; i++){
		for(int k = 0; k < num_DATA; k++){

			work_DIST[i][k] = BIG_NUM;
		}
	}

	for(int i = 1; i < num_DATA; i++){
		for(int k = 1; k < num_DATA; k++){
			if((k == i)||(num_city[DATA[i].country] < num_outer[DATA[i].country] && DATA[i].country == DATA[k].country))continue;

			int from_country = DATA[i].country;
			int from_city = DATA[i].right;

			if(DATA[k].left == -1){

				for(int a = 0; a < 4; a++){

					calc_DIST[i][k][a] = BIG_NUM;
				}

				int to_country = DATA[k].country;

				for(int a = 0; a < info[to_country][STATE[to_country]].num_L; a++){

					int to_city = info[to_country][STATE[to_country]].L[a];
					calc_DIST[i][k][a] = DIST[from_country][from_city][to_country][to_city];
				}

				continue;
			}

			int to_country = DATA[k].country;
			int to_city = DATA[k].left;

			if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

			work_DIST[i][k] = DIST[from_country][from_city][to_country][to_city];
		}
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		int state = table[num_DATA][i];
		for(int k = 0; k < num_LAST[num_DATA][state]; k++){

			DP[state][LAST[num_DATA][state][k]] = BIG_NUM;
		}
	}
	for(int last = 1; last < num_DATA; last++){

		DP[POW[num_DATA]-1][last] = BIG_NUM;
	}

	for(int k = 1; k < num_DATA; k++){
		if(info[0][STATE[0]].COUNT == -1){ //国0がnum2でない
				int from_country = 0;
				int from_city = DATA[0].right;

				if(DATA[k].left != -1){

					int to_country = DATA[k].country;
					int to_city = DATA[k].left;

					if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

					DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],DIST[from_country][from_city][to_country][to_city]);
				}else{

					int to_country = DATA[k].country;
					for(int a = 0; a < info[to_country][STATE[to_country]].num_L; a++){

						int to_city = info[to_country][STATE[to_country]].L[a];

						if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

						DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],
								DIST[from_country][from_city][to_country][to_city]+info[to_country][STATE[to_country]].COST[a]);
					}
				}

		}else{ //国0がnum2

			int left = DATA[0].left;

			for(int right = left+1; right <= 3; right++){

				int from_country = 0;
				int from_city = right;

				if(DATA[k].left != -1){

					int to_country = DATA[k].country;
					int to_city = DATA[k].left;

					if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;
					int tmp_cost = info[0][STATE[0]].COST[right-(left+1)];
					if(tmp_cost == BIG_NUM)continue;

					DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],DIST[from_country][from_city][to_country][to_city]+tmp_cost);
				}else{

					int tmp_cost = info[0][STATE[0]].COST[right-(left+1)];
					if(tmp_cost == BIG_NUM)continue;

					int to_country = DATA[k].country;
					for(int a = 0; a < info[to_country][STATE[to_country]].num_L; a++){

						int to_city = info[to_country][STATE[to_country]].L[a];
						if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

						DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],
								DIST[from_country][from_city][to_country][to_city]+info[to_country][STATE[to_country]].COST[a]+tmp_cost);
					}
				}
			}
		}
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		int state = table[num_DATA][i];
		int max_k = num_LAST[num_DATA][state];
		for(int k = 0; k < max_k; k++){
			int last = LAST[num_DATA][state][k];
			if(DP[state][last]==BIG_NUM)continue;
			int max_a = num_NEXT[num_DATA][state][k];
			for(int a = 0; a < max_a; a++){
				int next = NEXT[num_DATA][state][k][a];
				if(DATA[next].left != -1){
					DP[state|(1<<next)][next] = min(DP[state|(1<<next)][next],DP[state][last]+work_DIST[last][next]);
				}else{

					int to_country = DATA[next].country;
					int max_b = info[to_country][STATE[to_country]].num_L;

					for(int b = 0; b < max_b; b++){
						if(calc_DIST[last][next][b] == BIG_NUM)continue;

						DP[state|(1<<next)][next] = min(DP[state|(1<<next)][next],
								DP[state][last]+calc_DIST[last][next][b]+info[to_country][STATE[to_country]].COST[b]);
					}
				}
			}
		}
	}

	int tmp_ans = BIG_NUM;

	for(int last = 1; last < num_DATA; last++){
		if(DP[POW[num_DATA]-1][last] == BIG_NUM)continue;

		int pre_country = DATA[last].country;
		int pre_city = DATA[last].right;

		int next_country = DATA[0].country;
		int next_city = DATA[0].left;

		if(DIST[pre_country][pre_city][next_country][next_city] == BIG_NUM)continue;

		if(tmp_ans > DP[POW[num_DATA]-1][last]+
				DIST[pre_country][pre_city][next_country][next_city]){
			tmp_ans = DP[POW[num_DATA]-1][last]+
					DIST[pre_country][pre_city][next_country][next_city];
		}
	}

	if(tmp_ans < BIG_NUM){

		ans = min(ans,tmp_ans+add);
	}
}

void calc_dp(int index){

	for(int start = 0; start < num_outer[index]; start++){
		for(int state = 0; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){

				work_dp[start][state][last] = BIG_NUM;
			}
		}
	}

	for(int i = 0; i < num_outer[index]; i++){
		work_dp[i][POW[i]][i] = 0;
		for(int state = 1; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){
				if(work_dp[i][state][last] == BIG_NUM)continue;

				for(int next = 0; next < num_city[index]; next++){
					if(state & POW[next])continue;
					if(DIST[index][last][index][next] == BIG_NUM)continue;

					int next_state = state+POW[next];
					int next_cost = work_dp[i][state][last]+DIST[index][last][index][next];

					work_dp[i][next_state][next] = min(work_dp[i][next_state][next],next_cost);
				}
			}
		}
	}
}

void calc_LAST_NEXT(){

	for(int i = 2; i <= 15; i++){
		int maximum = POW[i];
		num_STATE[i] = 0;
		for(int state = 3; state <= maximum-3; state += 2){ //DATA[0]を訪問済の状態のみ列挙

			table[i][num_STATE[i]++] = state;

			num_NOT[state] = 0;
			for(int k = 1; k < i; k++){
				if(state&POW[k])continue;
				NOT[state][num_NOT[state]++] = k;
			}

			num_LAST[i][state] = 0;

			for(int last = 1; last < i; last++){
				if((state&POW[last]) == 0)continue;

				LAST[i][state][num_LAST[i][state]] = last;
				num_NEXT[i][state][num_LAST[i][state]] = 0;

				for(int next = 1; next < i; next++){
					if(next == last)continue;
					if(state&POW[next])continue;

					NEXT[i][state][num_LAST[i][state]][num_NEXT[i][state][num_LAST[i][state]]++] = next;
				}
				num_LAST[i][state]++;
			}
		}
	}
}

int main(){

	POW[0] = 1;
	for(int i = 1; i <= SIZE; i++){

		POW[i] = POW[i-1]*2;
	}

	for(int a = 0; a < SIZE; a++){
		for(int b = 0; b < SIZE; b++){
			for(int c = 0; c < SIZE; c++){
				for(int d = 0; d < SIZE; d++){
					DIST[a][b][c][d] = BIG_NUM;
				}
			}
		}
	}

	for(int i = 0; i < SIZE; i++){
		for(int a = 0; a < 4; a++){
			for(int b = 0; b < 4; b++){
				pair_used[i][a][b] = false;
				for(int c = 0; c < 4; c++){
					for(int d = 0; d < 4; d++){
						used[i][a][b][c][d] = false;
					}
				}
			}
		}
	}

	scanf("%d %d",&N,&K);

	for(int i = 0; i < N; i++){
		input[i].index = i;
		scanf("%d",&input[i].CITY);
	}

	for(int i = 0; i < N; i++){

		scanf("%d",&input[i].OUTER);
	}

	sort(input,input+N);

	for(int i = 0; i < N; i++){
		MAP[input[i].index] = i;
		num_city[i] = input[i].CITY;
		num_outer[i] = input[i].OUTER;
	}

	int from_country,from_city,to_country,to_city,cost;

	for(int i = 0; i < K; i++){

		scanf("%d %d %d %d %d",&from_country,&from_city,&to_country,&to_city,&cost);
		from_country--;
		from_city--;
		to_country--;
		to_city--;

		from_country = MAP[from_country];
		to_country = MAP[to_country];

		if(from_country == to_country){

			same_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			same_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));

		}else{

			diff_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			diff_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));
		}

		DIST[from_country][from_city][to_country][to_city] = cost;
		DIST[to_country][to_city][from_country][from_city] = cost;
	}

	if(N == 1){

		calc_one();
		return 0;
	}

	calc_LAST_NEXT();
	int start = 0;

	if(num_outer[0] == 4 && num_city[0] > 4){
		calc_dp(0);
		start = 1;
		calc_zero(num_outer[0]);
	}

	for(int i = start; i < N; i++){

		if(num_outer[i] == 1){

			int IN[4] = {0,-1,-1,-1};
			int OUT[4] = {0,-1,-1,-1};
			int COST[3] = {0,-1,-1};
			int L[3];

			if(num_city[i] > 1){

				printf("-1\n");
				return 0;

			}else{

				info[i].push_back(Info(1,IN,OUT,COST,-1,0,L));
			}

		}else if(num_outer[i] == 2){

			calc_dp(i);
			calc_2(i);

		}else if(num_outer[i] == 3){

			calc_dp(i);

			calc_2(i);
			calc_3(i);


		}else{ //num_outer[i] == 4

			calc_dp(i);

			if(num_city[i] > 4){
				calc_2(i);
				calc_3(i);
			}
			int work_4[4];
			for(int a = 0; a < 4; a++){

				work_4[a] = a;
			}
			calc_4(i,work_4);
		}
	}

	for(int i = 0; i < N; i++){
		if(info[i].size() == 0){

			printf("-1\n");
			return 0;
		}
	}


	ans = BIG_NUM;
	recursive(0);

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}

	return 0;
}
accuracy: 1
time_ms: 3010
memory_kb: 169448
final_rank: 2

code_snippet: #include<bits/stdc++.h>
/*m(_ _)m申し訳ございません*/
#pragma GCC target("avx")
#pragma GCC optimize("O3")
/*m(_ _)m申し訳ございません*/
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 15
#define NUM 32768

struct Edge{
	Edge(int arg_to_country,int arg_to_city,int arg_cost){
		to_country = arg_to_country;
		to_city = arg_to_city;
		cost = arg_cost;
	}
	int to_country,to_city,cost;
};

struct INPUT{
	bool operator<(const struct INPUT &arg) const{

		if(OUTER != arg.OUTER){
			return OUTER > arg.OUTER;
		}else{
			return CITY > arg.CITY;
		}
	}
	int index,CITY,OUTER;
};

struct Edge2{
	Edge2(int arg_to,int arg_cost){
		to = arg_to;
		cost = arg_cost;
	}
	int to,cost;
};

struct Info{
	Info(int arg_num_out,int arg_IN[4],int arg_OUT[4],int arg_COST[3],int arg_COUNT,int arg_num_L,int arg_L[3]){
		num_out = arg_num_out;
		for(int i = 0; i < num_out; i++){
			IN[i] = arg_IN[i];
			OUT[i] = arg_OUT[i];
		}
		for(int i = 0; i < 3; i++){

			COST[i] = arg_COST[i];
			L[i] = arg_L[i];
		}
		num_L = arg_num_L;
		COUNT = arg_COUNT;
	}
	int num_out,IN[4],OUT[4],COST[3],num_L,L[3],COUNT;
};

struct Data{
	void set(int arg_country,int arg_left,int arg_right){
		country = arg_country;
		left = arg_left;
		right = arg_right;
	}
	int country;
	int left,right;
};

struct DEBUG{

	int pre_state,pre_node;
};

int N,K;
int num_city[SIZE],num_outer[SIZE];
int POW[SIZE+1];
int STATE[SIZE];
int ONE[NUM][SIZE];
int DIST[SIZE][SIZE][SIZE][SIZE];
int work_dp[SIZE][NUM][SIZE];
int DP[NUM][SIZE];
int ans;
int num_STATE[SIZE+1];
int table[SIZE+1][NUM];
int LAST[SIZE+1][NUM][SIZE+1],num_LAST[SIZE+1][NUM];
int NEXT[SIZE+1][NUM][SIZE+1][SIZE+1];
int num_NEXT[SIZE+1][NUM][SIZE+1];
int NOT[NUM][SIZE+1],num_NOT[NUM];
bool used[SIZE][4][4][4][4],pair_used[SIZE][4][4];
Data DATA[SIZE];
vector<Edge> same_G[SIZE][SIZE],diff_G[SIZE][SIZE];
vector<Info> info[SIZE];
map<int,int> MAP;
INPUT input[SIZE+1];


void calc_2(int index){

	if(num_city[index] == 2){ //立ち寄り2回

		int IN[4] = {0,1,-1,-1};
		int OUT[4] = {0,1,-1,-1};
		int COST[3] = {0,-1,-1};
		int L[3];

		info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));

	}else{ //?入りsecond出

		if(index == 0){

			int work[num_outer[index]];
			for(int i = 0; i < num_outer[index]; i++){

				work[i] = i;
			}

			do{

				int first = work[0];
				int second = work[1];
				if(first > second)continue;
				if(work_dp[first][POW[num_city[0]]-1][second] == BIG_NUM)continue;

				int IN[3] = {first,-1,-1};
				int OUT[3] = {second,-1,-1};
				int COST[3] = {work_dp[first][POW[num_city[0]]-1][second],-1,-1};
				int L[3];

				info[0].push_back(Info(1,IN,OUT,COST,-1,0,L));

			}while(next_permutation(work,work+num_outer[index]));

			return;
		}

		for(int second = 0; second < num_outer[index]; second++){
			int num_L = 0;
			int IN[3] = {-1,-1,-1};
			int OUT[3] = {second,-1,-1};
			int COST[3] = {-1,-1,-1};
			int L[3];

			for(int first = 0; first < num_outer[index]; first++){
				if(first == second)continue;
				if(work_dp[first][POW[num_city[index]]-1][second] == BIG_NUM)continue;

				COST[num_L] = work_dp[first][POW[num_city[index]]-1][second];
				L[num_L++] = first;
			}
			if(num_L == 0)continue;
			if(num_L == 1){
				IN[0] = L[0];
				info[index].push_back(Info(1,IN,OUT,COST,-1,0,L));
			}else{
				info[index].push_back(Info(1,IN,OUT,COST,2,num_L,L));
			}
		}
	}
}

void calc_3(int index){

	if(num_outer[index] == 3){

		if(num_city[index] == 3){ //立ち寄り3回

			int IN[4] = {0,1,2,-1};
			int OUT[4] = {0,1,2,-1};
			int COST[3] = {0,-1,-1};
			int L[3];

			info[index].push_back(Info(3,IN,OUT,COST,-1,0,L));

		}else{ //first立ち寄り,second入りthird出

			int work[4] = {0,1,2,3};

			do{
				int first = work[0];
				int second = work[1];
				int third = work[2];

				int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

				if(work_dp[second][to_state][third] < BIG_NUM){

					int IN[4] = {first,second,-1,-1};
					int OUT[4] = {first,third,-1,-1};
					int COST[3] = {work_dp[second][to_state][third],-1,-1};
					int L[3];

					info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));
				}

			}while(next_permutation(work,work+3));
		}
	}else{ //num_outer[index] == 4

		for(int first = 0; first < 4; first++){
			for(int third = 0; third < 4; third++){
				if(third == first)continue;

				int IN[4] = {first,-1,-1,-1};
				int OUT[4] = {first,third,-1,-1};
				int COST[3] = {-1,-1,-1};
				int L[3] = {-1,-1,-1};

				int num_L = 0;

				for(int second = 0; second < 4; second++){
					if(second == first || second == third || (index == 0 && second >third))continue;

					int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

					if(work_dp[second][to_state][third] < BIG_NUM){

						COST[num_L] = work_dp[second][to_state][third];
						L[num_L++] = second;
					}
				}
				if(num_L == 0)continue;
				if(num_L == 1){

					IN[1] = L[0];
					info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));
				}else{

					info[index].push_back(Info(2,IN,OUT,COST,3,num_L,L));
				}
			}
		}
	}
}

void calc_4(int index,int work[4]){

	int L[3];

	if(num_city[index] == 4){ //立ち寄り4回

		int IN[4] = {work[0],work[1],work[2],work[3]};
		int OUT[4] = {work[0],work[1],work[2],work[3]};
		int COST[3] = {0,-1,-1};

		info[index].push_back(Info(4,IN,OUT,COST,-1,0,L));

	}else{

		do{

			int a = work[0];
			int b = work[1];
			int c = work[2];
			int d = work[3];

			//a入りb出-c入d出
			if(!used[index][c][d][a][b]){
				used[index][a][b][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[c]+POW[d]);
				int tmp_cost = BIG_NUM;

				for(int from_state = 1; from_state <= to_state; from_state++){
					if(((from_state & POW[c]) == POW[c]) ||
						((from_state & POW[d]) == POW[d]) ||
						((from_state & POW[a]) != POW[a]) ||
						((from_state & POW[b]) != POW[b]))continue;
					if(work_dp[a][from_state][b] == BIG_NUM)continue;

					int rest_state = POW[num_city[index]]-1-from_state;
					if(work_dp[c][rest_state][d] == BIG_NUM)continue;

					tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
				}

				if(tmp_cost < BIG_NUM){

					int IN[4] = {a,c,-1,-1};
					int OUT[4] = {b,d,-1,-1};
					int COST[3] = {tmp_cost,-1,-1};

					info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));
				}
			}

			//a,b立ち寄り,c入d出
			if(!pair_used[index][c][d]){
				pair_used[index][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[a]+POW[b]);

				if(work_dp[c][to_state][d] < BIG_NUM){

					int IN[4] = {a,b,c,-1};
					int OUT[4] = {a,b,d,-1};
					int COST[3] = {work_dp[c][to_state][d],-1,-1};

					info[index].push_back(Info(3,IN,OUT,COST,-1,0,L));
				}
			}

		}while(next_permutation(work,work+4));
	}
}

void calc_zero(int count_outer){

	int L[3];

	for(int left = 0; left <= 2; left++){
		int IN[4] = {left,-1,-1,-1};
		int OUT[4] = {-1,-1,-1,-1};

		int COST[3];
		for(int i = 0; i < 3; i++){

			COST[i] = -1;
		}
		for(int right = left+1; right <= 3; right++){

			COST[right-(left+1)] = work_dp[left][POW[num_city[0]]-1][right]; //left入りright出
		}

		info[0].push_back(Info(1,IN,OUT,COST,2,0,L));
	}

	int first,second,third;

	int work[4] = {0,1,2,3};

	do{
		first = work[0];
		second = work[1];
		third = work[2];
		if(second > third)continue;

		int to_state = (POW[num_city[0]]-1)-POW[first]; //firstを除いてTSP

		if(work_dp[second][to_state][third] < BIG_NUM){

			int IN[4] = {first,second,-1,-1};
			int OUT[4] = {first,third,-1,-1};
			int COST[3] = {work_dp[second][to_state][third],-1,-1};

			info[0].push_back(Info(2,IN,OUT,COST,-1,0,L));
		}

	}while(next_permutation(work,work+4));

	int a,b,c,d;
	for(int loop = 0; loop < 6; loop++){
		if(loop == 0){
			a = 0;
			b = 1;
			c = 2;
			d = 3;
		}else if(loop == 1){
			a = 0;
			b = 1;
			c = 3;
			d = 2;
		}else if(loop == 2){
			a = 0;
			b = 2;
			c = 1;
			d = 3;
		}else if(loop == 3){
			a = 0;
			b = 2;
			c = 3;
			d = 1;
		}else if(loop == 4){
			a = 0;
			b = 3;
			c = 1;
			d = 2;
		}else{ //loop == 5
			a = 0;
			b = 3;
			c = 2;
			d = 1;
		}

		//a入りb出-c入d出
		int to_state = (POW[num_city[0]]-1)-(POW[c]+POW[d]);
		int tmp_cost = BIG_NUM;

		for(int from_state = 1; from_state <= to_state; from_state++){
			if(((from_state & POW[c]) == POW[c]) ||
				((from_state & POW[d]) == POW[d]) ||
				((from_state & POW[a]) != POW[a]) ||
				((from_state & POW[b]) != POW[b]))continue;
			if(work_dp[a][from_state][b] == BIG_NUM)continue;

			int rest_state = POW[num_city[0]]-1-from_state;
			if(work_dp[c][rest_state][d] == BIG_NUM)continue;

			tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
		}

		if(tmp_cost < BIG_NUM){

			int IN[4] = {a,c,-1,-1};
			int OUT[4] = {b,d,-1,-1};
			int COST[3] = {tmp_cost,-1,-1};

			info[0].push_back(Info(2,IN,OUT,COST,-1,0,L));
		}
	}

	for(int loop = 0; loop < 6; loop++){
		if(loop == 0){
			a = 2;
			b = 3;
			c = 0;
			d = 1;
		}else if(loop == 1){
			a = 1;
			b = 3;
			c = 0;
			d = 2;
		}else if(loop == 2){
			a = 1;
			b = 2;
			c = 0;
			d = 3;
		}else if(loop == 3){
			a = 0;
			b = 3;
			c = 1;
			d = 2;
		}else if(loop == 4){
			a = 0;
			b = 2;
			c = 1;
			d = 3;
		}else{ //loop == 5
			a = 0;
			b = 1;
			c = 2;
			d = 3;
		}

		//a,b立ち寄り,c入d出
		int to_state = (POW[num_city[0]]-1)-(POW[a]+POW[b]);

		if(work_dp[c][to_state][d] < BIG_NUM){

			int IN[4] = {a,b,c,-1};
			int OUT[4] = {a,b,d,-1};
			int COST[3] = {work_dp[c][to_state][d],-1,-1};
			info[0].push_back(Info(3,IN,OUT,COST,-1,0,L));
		}
	}
}

void calc_one(){

	if(num_city[0] == 1){

		printf("0\n");
		return;
	}

	int index = 0;

	for(int state = 0; state < POW[num_city[index]]; state++){
		for(int last = 0; last < num_city[index]; last++){

			ONE[state][last] = BIG_NUM;
		}
	}

	//経路は輪になるので、スタートは0として良いはず
	ONE[POW[0]][0] = 0;

	for(int state = 1; state < POW[num_city[index]]-1; state++){
		for(int last = 0; last < num_city[index]; last++){
			if(ONE[state][last] == BIG_NUM)continue;

			for(int i = 0; i < same_G[index][last].size(); i++){

				int next_node = same_G[index][last][i].to_city;

				if(state & POW[next_node])continue;

				int next_state = state+POW[next_node];
				int next_cost = ONE[state][last]+same_G[index][last][i].cost;

				ONE[next_state][next_node] = min(ONE[next_state][next_node],next_cost);
			}
		}
	}

	int ans = BIG_NUM;
	for(int last = 0; last < num_city[index]; last++){
		if(ONE[POW[num_city[index]]-1][last] == BIG_NUM)continue;

		ans = min(ans,ONE[POW[num_city[index]]-1][last]+DIST[0][last][0][0]);
	}

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}
}
void recursive(int index){

	if(index < N){

		for(int i = 0; i < info[index].size(); i++){

			STATE[index] = i;
			recursive(index+1);
		}
		return;
	}

	//index == N
	int num_DATA = 0;
	int add = 0;

	int work_DIST[SIZE][SIZE];
	for(int i = 0; i < SIZE; i++){
		for(int k = 0; k < SIZE; k++){

			work_DIST[i][k] = BIG_NUM;
		}
	}

	for(int i = 0; i < N; i++){
		int num = STATE[i];
		if(info[i][num].COUNT == -1){
			add += info[i][num].COST[0];
		}
		for(int k = 0; k < info[i][num].num_out; k++){

			DATA[num_DATA++].set(i,info[i][num].IN[k],info[i][STATE[i]].OUT[k]);
		}
	}

	if(add >= ans)return;

	for(int i = 1; i < num_DATA; i++){
		for(int k = 1; k < num_DATA; k++){
			if((k == i)||(num_city[DATA[i].country] < num_outer[DATA[i].country] && DATA[i].country == DATA[k].country))continue;
			if(DATA[k].left == -1)continue;

			int from_country = DATA[i].country;
			int from_city = DATA[i].right;

			int to_country = DATA[k].country;
			int to_city = DATA[k].left;

			if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

			work_DIST[i][k] = DIST[from_country][from_city][to_country][to_city];
		}
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		int state = table[num_DATA][i];
		for(int k = 0; k < num_LAST[num_DATA][state]; k++){

			DP[state][LAST[num_DATA][state][k]] = BIG_NUM;
		}
	}
	for(int last = 1; last < num_DATA; last++){

		DP[POW[num_DATA]-1][last] = BIG_NUM;
	}

	for(int k = 1; k < num_DATA; k++){
		if(info[0][STATE[0]].COUNT == -1){ //国0がnum2でない
				int from_country = 0;
				int from_city = DATA[0].right;

				if(DATA[k].left != -1){

					int to_country = DATA[k].country;
					int to_city = DATA[k].left;

					if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

					DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],DIST[from_country][from_city][to_country][to_city]);
				}else{

					int to_country = DATA[k].country;
					for(int a = 0; a < info[to_country][STATE[to_country]].num_L; a++){

						int to_city = info[to_country][STATE[to_country]].L[a];

						if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

						DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],
								DIST[from_country][from_city][to_country][to_city]+info[to_country][STATE[to_country]].COST[a]);
					}
				}

		}else{ //国0がnum2

			int left = DATA[0].left;

			for(int right = left+1; right <= 3; right++){

				int from_country = 0;
				int from_city = right;

				if(DATA[k].left != -1){

					int to_country = DATA[k].country;
					int to_city = DATA[k].left;

					if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;
					int tmp_cost = info[0][STATE[0]].COST[right-(left+1)];
					if(tmp_cost == BIG_NUM)continue;

					DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],DIST[from_country][from_city][to_country][to_city]+tmp_cost);
				}else{

					int tmp_cost = info[0][STATE[0]].COST[right-(left+1)];
					if(tmp_cost == BIG_NUM)continue;

					int to_country = DATA[k].country;
					for(int a = 0; a < info[to_country][STATE[to_country]].num_L; a++){

						int to_city = info[to_country][STATE[to_country]].L[a];
						if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

						DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],
								DIST[from_country][from_city][to_country][to_city]+info[to_country][STATE[to_country]].COST[a]+tmp_cost);
					}
				}
			}
		}
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		int state = table[num_DATA][i];
		int max_k = num_LAST[num_DATA][state];
		for(int k = 0; k < max_k; k++){
			int last = LAST[num_DATA][state][k];
			if(DP[state][last]==BIG_NUM)continue;
			int max_a = num_NEXT[num_DATA][state][k];
			for(int a = 0; a < max_a; a++){
				int next = NEXT[num_DATA][state][k][a];
				if(DATA[next].left != -1){
					DP[state|(1<<next)][next] = min(DP[state|(1<<next)][next],DP[state][last]+work_DIST[last][next]);
				}else{

					int from_country = DATA[last].country;
					int from_city = DATA[last].right;

					int to_country = DATA[next].country;
					int max_b = info[to_country][STATE[to_country]].num_L;

					for(int b = 0; b < max_b; b++){
						int to_city = info[to_country][STATE[to_country]].L[b];
						if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

						DP[state|(1<<next)][next] = min(DP[state|(1<<next)][next],
								DP[state][last]+DIST[from_country][from_city][to_country][to_city]+info[to_country][STATE[to_country]].COST[b]);
					}
				}
			}
		}
	}

	int tmp_ans = BIG_NUM;

	for(int last = 1; last < num_DATA; last++){
		if(DP[POW[num_DATA]-1][last] == BIG_NUM)continue;

		int pre_country = DATA[last].country;
		int pre_city = DATA[last].right;

		int next_country = DATA[0].country;
		int next_city = DATA[0].left;

		if(DIST[pre_country][pre_city][next_country][next_city] == BIG_NUM)continue;

		if(tmp_ans > DP[POW[num_DATA]-1][last]+
				DIST[pre_country][pre_city][next_country][next_city]){
			tmp_ans = DP[POW[num_DATA]-1][last]+
					DIST[pre_country][pre_city][next_country][next_city];
		}
	}

	if(tmp_ans < BIG_NUM){

		ans = min(ans,tmp_ans+add);
	}
}

void calc_dp(int index){

	for(int start = 0; start < num_outer[index]; start++){
		for(int state = 0; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){

				work_dp[start][state][last] = BIG_NUM;
			}
		}
	}

	for(int i = 0; i < num_outer[index]; i++){
		work_dp[i][POW[i]][i] = 0;
		for(int state = 1; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){
				if(work_dp[i][state][last] == BIG_NUM)continue;

				for(int next = 0; next < num_city[index]; next++){
					if(state & POW[next])continue;
					if(DIST[index][last][index][next] == BIG_NUM)continue;

					int next_state = state+POW[next];
					int next_cost = work_dp[i][state][last]+DIST[index][last][index][next];

					work_dp[i][next_state][next] = min(work_dp[i][next_state][next],next_cost);
				}
			}
		}
	}
}

void calc_LAST_NEXT(){

	for(int i = 2; i <= 15; i++){
		int maximum = POW[i];
		num_STATE[i] = 0;
		for(int state = 3; state <= maximum-3; state += 2){ //DATA[0]を訪問済の状態のみ列挙

			table[i][num_STATE[i]++] = state;

			num_NOT[state] = 0;
			for(int k = 1; k < i; k++){
				if(state&POW[k])continue;
				NOT[state][num_NOT[state]++] = k;
			}

			num_LAST[i][state] = 0;

			for(int last = 1; last < i; last++){
				if((state&POW[last]) == 0)continue;

				LAST[i][state][num_LAST[i][state]] = last;
				num_NEXT[i][state][num_LAST[i][state]] = 0;

				for(int next = 1; next < i; next++){
					if(next == last)continue;
					if(state&POW[next])continue;

					NEXT[i][state][num_LAST[i][state]][num_NEXT[i][state][num_LAST[i][state]]++] = next;
				}
				num_LAST[i][state]++;
			}
		}
	}
}

int main(){

	POW[0] = 1;
	for(int i = 1; i <= SIZE; i++){

		POW[i] = POW[i-1]*2;
	}

	for(int a = 0; a < SIZE; a++){
		for(int b = 0; b < SIZE; b++){
			for(int c = 0; c < SIZE; c++){
				for(int d = 0; d < SIZE; d++){
					DIST[a][b][c][d] = BIG_NUM;
				}
			}
		}
	}

	for(int i = 0; i < SIZE; i++){
		for(int a = 0; a < 4; a++){
			for(int b = 0; b < 4; b++){
				pair_used[i][a][b] = false;
				for(int c = 0; c < 4; c++){
					for(int d = 0; d < 4; d++){
						used[i][a][b][c][d] = false;
					}
				}
			}
		}
	}

	scanf("%d %d",&N,&K);

	for(int i = 0; i < N; i++){
		input[i].index = i;
		scanf("%d",&input[i].CITY);
	}

	for(int i = 0; i < N; i++){

		scanf("%d",&input[i].OUTER);
	}

	sort(input,input+N);

	for(int i = 0; i < N; i++){
		MAP[input[i].index] = i;
		num_city[i] = input[i].CITY;
		num_outer[i] = input[i].OUTER;
	}

	int from_country,from_city,to_country,to_city,cost;

	for(int i = 0; i < K; i++){

		scanf("%d %d %d %d %d",&from_country,&from_city,&to_country,&to_city,&cost);
		from_country--;
		from_city--;
		to_country--;
		to_city--;

		from_country = MAP[from_country];
		to_country = MAP[to_country];

		if(from_country == to_country){

			same_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			same_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));

		}else{

			diff_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			diff_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));
		}

		DIST[from_country][from_city][to_country][to_city] = cost;
		DIST[to_country][to_city][from_country][from_city] = cost;
	}

	if(N == 1){

		calc_one();
		return 0;
	}

	calc_LAST_NEXT();
	int start = 0;

	if(num_outer[0] == 4 && num_city[0] > 4){
		calc_dp(0);
		start = 1;
		calc_zero(num_outer[0]);
	}

	for(int i = start; i < N; i++){

		if(num_outer[i] == 1){

			int IN[4] = {0,-1,-1,-1};
			int OUT[4] = {0,-1,-1,-1};
			int COST[3] = {0,-1,-1};
			int L[3];

			if(num_city[i] > 1){

				printf("-1\n");
				return 0;

			}else{

				info[i].push_back(Info(1,IN,OUT,COST,-1,0,L));
			}

		}else if(num_outer[i] == 2){

			calc_dp(i);
			calc_2(i);

		}else if(num_outer[i] == 3){

			calc_dp(i);

			calc_2(i);
			calc_3(i);


		}else{ //num_outer[i] == 4

			calc_dp(i);

			if(num_city[i] > 4){
				calc_2(i);
				calc_3(i);
			}
			int work_4[4];
			for(int a = 0; a < 4; a++){

				work_4[a] = a;
			}
			calc_4(i,work_4);
		}
	}

	for(int i = 0; i < N; i++){
		if(info[i].size() == 0){

			printf("-1\n");
			return 0;
		}
	}


	ans = BIG_NUM;
	recursive(0);

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}

	return 0;
}
accuracy: 1
time_ms: 3050
memory_kb: 169456
final_rank: 3

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 15
#define NUM 32768

struct Edge{
	Edge(int arg_to_country,int arg_to_city,int arg_cost){
		to_country = arg_to_country;
		to_city = arg_to_city;
		cost = arg_cost;
	}
	int to_country,to_city,cost;
};

struct INPUT{
	bool operator<(const struct INPUT &arg) const{

		if(OUTER != arg.OUTER){
			return OUTER > arg.OUTER;
		}else{
			return CITY > arg.CITY;
		}
	}
	int index,CITY,OUTER;
};

struct Edge2{
	Edge2(int arg_to,int arg_cost){
		to = arg_to;
		cost = arg_cost;
	}
	int to,cost;
};

struct Info{
	Info(int arg_num_out,int arg_IN[4],int arg_OUT[4],int arg_COST[3],int arg_COUNT,int arg_num_L,int arg_L[3]){
		num_out = arg_num_out;
		for(int i = 0; i < num_out; i++){
			IN[i] = arg_IN[i];
			OUT[i] = arg_OUT[i];
		}
		for(int i = 0; i < 3; i++){

			COST[i] = arg_COST[i];
			L[i] = arg_L[i];
		}
		num_L = arg_num_L;
		COUNT = arg_COUNT;
	}
	int num_out,IN[4],OUT[4],COST[3],num_L,L[3],COUNT;
};

struct Data{
	void set(int arg_country,int arg_left,int arg_right){
		country = arg_country;
		left = arg_left;
		right = arg_right;
	}
	int country;
	int left,right;
};

struct DEBUG{

	int pre_state,pre_node;
};

int N,K;
int num_city[SIZE],num_outer[SIZE];
int POW[SIZE+1];
int STATE[SIZE];
int ONE[NUM][SIZE];
int DIST[SIZE][SIZE][SIZE][SIZE];
int work_dp[SIZE][NUM][SIZE];
int DP[NUM][SIZE];
int ans;
int num_STATE[SIZE+1];
int table[SIZE+1][NUM];
int LAST[SIZE+1][NUM][SIZE+1],num_LAST[SIZE+1][NUM];
int NEXT[SIZE+1][NUM][SIZE+1][SIZE+1];
int num_NEXT[SIZE+1][NUM][SIZE+1];
int NOT[NUM][SIZE+1],num_NOT[NUM];
bool used[SIZE][4][4][4][4],pair_used[SIZE][4][4];
Data DATA[SIZE];
vector<Edge> same_G[SIZE][SIZE],diff_G[SIZE][SIZE];
vector<Info> info[SIZE];
map<int,int> MAP;
INPUT input[SIZE+1];


void calc_2(int index){

	if(num_city[index] == 2){ //立ち寄り2回

		int IN[4] = {0,1,-1,-1};
		int OUT[4] = {0,1,-1,-1};
		int COST[3] = {0,-1,-1};
		int L[3];

		info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));

	}else{ //?入りsecond出

		if(index == 0){

			int work[num_outer[index]];
			for(int i = 0; i < num_outer[index]; i++){

				work[i] = i;
			}

			do{

				int first = work[0];
				int second = work[1];
				if(first > second)continue;
				if(work_dp[first][POW[num_city[0]]-1][second] == BIG_NUM)continue;

				int IN[3] = {first,-1,-1};
				int OUT[3] = {second,-1,-1};
				int COST[3] = {work_dp[first][POW[num_city[0]]-1][second],-1,-1};
				int L[3];

				info[0].push_back(Info(1,IN,OUT,COST,-1,0,L));

			}while(next_permutation(work,work+num_outer[index]));

			return;
		}

		for(int second = 0; second < num_outer[index]; second++){
			int num_L = 0;
			int IN[3] = {-1,-1,-1};
			int OUT[3] = {second,-1,-1};
			int COST[3] = {-1,-1,-1};
			int L[3];

			for(int first = 0; first < num_outer[index]; first++){
				if(first == second)continue;
				if(work_dp[first][POW[num_city[index]]-1][second] == BIG_NUM)continue;

				COST[num_L] = work_dp[first][POW[num_city[index]]-1][second];
				L[num_L++] = first;
			}
			if(num_L == 0)continue;
			if(num_L == 1){
				IN[0] = L[0];
				info[index].push_back(Info(1,IN,OUT,COST,-1,0,L));
			}else{
				info[index].push_back(Info(1,IN,OUT,COST,2,num_L,L));
			}
		}
	}
}

void calc_3(int index){

	if(num_outer[index] == 3){

		if(num_city[index] == 3){ //立ち寄り3回

			int IN[4] = {0,1,2,-1};
			int OUT[4] = {0,1,2,-1};
			int COST[3] = {0,-1,-1};
			int L[3];

			info[index].push_back(Info(3,IN,OUT,COST,-1,0,L));

		}else{ //first立ち寄り,second入りthird出

			int work[4] = {0,1,2,3};

			do{
				int first = work[0];
				int second = work[1];
				int third = work[2];

				int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

				if(work_dp[second][to_state][third] < BIG_NUM){

					int IN[4] = {first,second,-1,-1};
					int OUT[4] = {first,third,-1,-1};
					int COST[3] = {work_dp[second][to_state][third],-1,-1};
					int L[3];

					info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));
				}

			}while(next_permutation(work,work+3));
		}
	}else{ //num_outer[index] == 4

		for(int first = 0; first < 4; first++){
			for(int third = 0; third < 4; third++){
				if(third == first)continue;

				int IN[4] = {first,-1,-1,-1};
				int OUT[4] = {first,third,-1,-1};
				int COST[3] = {-1,-1,-1};
				int L[3] = {-1,-1,-1};

				int num_L = 0;

				for(int second = 0; second < 4; second++){
					if(second == first || second == third || (index == 0 && second >third))continue;

					int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

					if(work_dp[second][to_state][third] < BIG_NUM){

						COST[num_L] = work_dp[second][to_state][third];
						L[num_L++] = second;
					}
				}
				if(num_L == 0)continue;
				if(num_L == 1){

					IN[1] = L[0];
					info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));
				}else{

					info[index].push_back(Info(2,IN,OUT,COST,3,num_L,L));
				}
			}
		}
	}
}

void calc_4(int index,int work[4]){

	int L[3];

	if(num_city[index] == 4){ //立ち寄り4回

		int IN[4] = {work[0],work[1],work[2],work[3]};
		int OUT[4] = {work[0],work[1],work[2],work[3]};
		int COST[3] = {0,-1,-1};

		info[index].push_back(Info(4,IN,OUT,COST,-1,0,L));

	}else{

		do{

			int a = work[0];
			int b = work[1];
			int c = work[2];
			int d = work[3];

			//a入りb出-c入d出
			if(!used[index][c][d][a][b]){
				used[index][a][b][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[c]+POW[d]);
				int tmp_cost = BIG_NUM;

				for(int from_state = 1; from_state <= to_state; from_state++){
					if(((from_state & POW[c]) == POW[c]) ||
						((from_state & POW[d]) == POW[d]) ||
						((from_state & POW[a]) != POW[a]) ||
						((from_state & POW[b]) != POW[b]))continue;
					if(work_dp[a][from_state][b] == BIG_NUM)continue;

					int rest_state = POW[num_city[index]]-1-from_state;
					if(work_dp[c][rest_state][d] == BIG_NUM)continue;

					tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
				}

				if(tmp_cost < BIG_NUM){

					int IN[4] = {a,c,-1,-1};
					int OUT[4] = {b,d,-1,-1};
					int COST[3] = {tmp_cost,-1,-1};

					info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));
				}
			}

			//a,b立ち寄り,c入d出
			if(!pair_used[index][c][d]){
				pair_used[index][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[a]+POW[b]);

				if(work_dp[c][to_state][d] < BIG_NUM){

					int IN[4] = {a,b,c,-1};
					int OUT[4] = {a,b,d,-1};
					int COST[3] = {work_dp[c][to_state][d],-1,-1};

					info[index].push_back(Info(3,IN,OUT,COST,-1,0,L));
				}
			}

		}while(next_permutation(work,work+4));
	}
}

void calc_zero(int count_outer){

	int L[3];

	for(int left = 0; left <= 2; left++){
		int IN[4] = {left,-1,-1,-1};
		int OUT[4] = {-1,-1,-1,-1};

		int COST[3];
		for(int i = 0; i < 3; i++){

			COST[i] = -1;
		}
		for(int right = left+1; right <= 3; right++){

			COST[right-(left+1)] = work_dp[left][POW[num_city[0]]-1][right]; //left入りright出
		}

		info[0].push_back(Info(1,IN,OUT,COST,2,0,L));
	}

	int first,second,third;

	int work[4] = {0,1,2,3};

	do{
		first = work[0];
		second = work[1];
		third = work[2];
		if(second > third)continue;

		int to_state = (POW[num_city[0]]-1)-POW[first]; //firstを除いてTSP

		if(work_dp[second][to_state][third] < BIG_NUM){

			int IN[4] = {first,second,-1,-1};
			int OUT[4] = {first,third,-1,-1};
			int COST[3] = {work_dp[second][to_state][third],-1,-1};

			info[0].push_back(Info(2,IN,OUT,COST,-1,0,L));
		}

	}while(next_permutation(work,work+4));

	int a,b,c,d;
	for(int loop = 0; loop < 6; loop++){
		if(loop == 0){
			a = 0;
			b = 1;
			c = 2;
			d = 3;
		}else if(loop == 1){
			a = 0;
			b = 1;
			c = 3;
			d = 2;
		}else if(loop == 2){
			a = 0;
			b = 2;
			c = 1;
			d = 3;
		}else if(loop == 3){
			a = 0;
			b = 2;
			c = 3;
			d = 1;
		}else if(loop == 4){
			a = 0;
			b = 3;
			c = 1;
			d = 2;
		}else{ //loop == 5
			a = 0;
			b = 3;
			c = 2;
			d = 1;
		}

		//a入りb出-c入d出
		int to_state = (POW[num_city[0]]-1)-(POW[c]+POW[d]);
		int tmp_cost = BIG_NUM;

		for(int from_state = 1; from_state <= to_state; from_state++){
			if(((from_state & POW[c]) == POW[c]) ||
				((from_state & POW[d]) == POW[d]) ||
				((from_state & POW[a]) != POW[a]) ||
				((from_state & POW[b]) != POW[b]))continue;
			if(work_dp[a][from_state][b] == BIG_NUM)continue;

			int rest_state = POW[num_city[0]]-1-from_state;
			if(work_dp[c][rest_state][d] == BIG_NUM)continue;

			tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
		}

		if(tmp_cost < BIG_NUM){

			int IN[4] = {a,c,-1,-1};
			int OUT[4] = {b,d,-1,-1};
			int COST[3] = {tmp_cost,-1,-1};

			info[0].push_back(Info(2,IN,OUT,COST,-1,0,L));
		}
	}

	for(int loop = 0; loop < 6; loop++){
		if(loop == 0){
			a = 2;
			b = 3;
			c = 0;
			d = 1;
		}else if(loop == 1){
			a = 1;
			b = 3;
			c = 0;
			d = 2;
		}else if(loop == 2){
			a = 1;
			b = 2;
			c = 0;
			d = 3;
		}else if(loop == 3){
			a = 0;
			b = 3;
			c = 1;
			d = 2;
		}else if(loop == 4){
			a = 0;
			b = 2;
			c = 1;
			d = 3;
		}else{ //loop == 5
			a = 0;
			b = 1;
			c = 2;
			d = 3;
		}

		//a,b立ち寄り,c入d出
		int to_state = (POW[num_city[0]]-1)-(POW[a]+POW[b]);

		if(work_dp[c][to_state][d] < BIG_NUM){

			int IN[4] = {a,b,c,-1};
			int OUT[4] = {a,b,d,-1};
			int COST[3] = {work_dp[c][to_state][d],-1,-1};
			info[0].push_back(Info(3,IN,OUT,COST,-1,0,L));
		}
	}
}

void calc_one(){

	if(num_city[0] == 1){

		printf("0\n");
		return;
	}

	int index = 0;

	for(int state = 0; state < POW[num_city[index]]; state++){
		for(int last = 0; last < num_city[index]; last++){

			ONE[state][last] = BIG_NUM;
		}
	}

	//経路は輪になるので、スタートは0として良いはず
	ONE[POW[0]][0] = 0;

	for(int state = 1; state < POW[num_city[index]]-1; state++){
		for(int last = 0; last < num_city[index]; last++){
			if(ONE[state][last] == BIG_NUM)continue;

			for(int i = 0; i < same_G[index][last].size(); i++){

				int next_node = same_G[index][last][i].to_city;

				if(state & POW[next_node])continue;

				int next_state = state+POW[next_node];
				int next_cost = ONE[state][last]+same_G[index][last][i].cost;

				ONE[next_state][next_node] = min(ONE[next_state][next_node],next_cost);
			}
		}
	}

	int ans = BIG_NUM;
	for(int last = 0; last < num_city[index]; last++){
		if(ONE[POW[num_city[index]]-1][last] == BIG_NUM)continue;

		ans = min(ans,ONE[POW[num_city[index]]-1][last]+DIST[0][last][0][0]);
	}

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}
}
void recursive(int index){

	if(index < N){

		for(int i = 0; i < info[index].size(); i++){

			STATE[index] = i;
			recursive(index+1);
		}
		return;
	}

	//index == N
	int num_DATA = 0;
	int add = 0;

	int work_DIST[SIZE][SIZE];
	for(int i = 0; i < SIZE; i++){
		for(int k = 0; k < SIZE; k++){

			work_DIST[i][k] = BIG_NUM;
		}
	}

	for(int i = 0; i < N; i++){
		int num = STATE[i];
		if(info[i][num].COUNT == -1){
			add += info[i][num].COST[0];
		}
		for(int k = 0; k < info[i][num].num_out; k++){

			DATA[num_DATA++].set(i,info[i][num].IN[k],info[i][STATE[i]].OUT[k]);
		}
	}

	if(add >= ans)return;

	for(int i = 1; i < num_DATA; i++){
		for(int k = 1; k < num_DATA; k++){
			if((k == i)||(num_city[DATA[i].country] < num_outer[DATA[i].country] && DATA[i].country == DATA[k].country))continue;
			if(DATA[k].left == -1)continue;

			int from_country = DATA[i].country;
			int from_city = DATA[i].right;

			int to_country = DATA[k].country;
			int to_city = DATA[k].left;

			if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

			work_DIST[i][k] = DIST[from_country][from_city][to_country][to_city];
		}
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		int state = table[num_DATA][i];
		for(int k = 0; k < num_LAST[num_DATA][state]; k++){

			DP[state][LAST[num_DATA][state][k]] = BIG_NUM;
		}
	}
	for(int last = 1; last < num_DATA; last++){

		DP[POW[num_DATA]-1][last] = BIG_NUM;
	}

	for(int k = 1; k < num_DATA; k++){
		if(info[0][STATE[0]].COUNT == -1){ //国0がnum2でない
				int from_country = 0;
				int from_city = DATA[0].right;

				if(DATA[k].left != -1){

					int to_country = DATA[k].country;
					int to_city = DATA[k].left;

					if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

					DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],DIST[from_country][from_city][to_country][to_city]);
				}else{

					int to_country = DATA[k].country;
					for(int a = 0; a < info[to_country][STATE[to_country]].num_L; a++){

						int to_city = info[to_country][STATE[to_country]].L[a];

						if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

						DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],
								DIST[from_country][from_city][to_country][to_city]+info[to_country][STATE[to_country]].COST[a]);
					}
				}

		}else{ //国0がnum2

			int left = DATA[0].left;

			for(int right = left+1; right <= 3; right++){

				int from_country = 0;
				int from_city = right;

				if(DATA[k].left != -1){

					int to_country = DATA[k].country;
					int to_city = DATA[k].left;

					if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;
					int tmp_cost = info[0][STATE[0]].COST[right-(left+1)];
					if(tmp_cost == BIG_NUM)continue;

					DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],DIST[from_country][from_city][to_country][to_city]+tmp_cost);
				}else{

					int tmp_cost = info[0][STATE[0]].COST[right-(left+1)];
					if(tmp_cost == BIG_NUM)continue;

					int to_country = DATA[k].country;
					for(int a = 0; a < info[to_country][STATE[to_country]].num_L; a++){

						int to_city = info[to_country][STATE[to_country]].L[a];
						if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

						DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],
								DIST[from_country][from_city][to_country][to_city]+info[to_country][STATE[to_country]].COST[a]+tmp_cost);
					}
				}
			}
		}
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		int state = table[num_DATA][i];
		int max_k = num_LAST[num_DATA][state];
		for(int k = 0; k < max_k; k++){
			int last = LAST[num_DATA][state][k];
			if(DP[state][last]==BIG_NUM)continue;
			int max_a = num_NEXT[num_DATA][state][k];
			for(int a = 0; a < max_a; a++){
				int next = NEXT[num_DATA][state][k][a];
				if(DATA[next].left != -1){
					DP[state|(1<<next)][next] = min(DP[state|(1<<next)][next],DP[state][last]+work_DIST[last][next]);
				}else{

					int from_country = DATA[last].country;
					int from_city = DATA[last].right;

					int to_country = DATA[next].country;
					int max_b = info[to_country][STATE[to_country]].num_L;

					for(int b = 0; b < max_b; b++){
						int to_city = info[to_country][STATE[to_country]].L[b];
						if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

						DP[state|(1<<next)][next] = min(DP[state|(1<<next)][next],
								DP[state][last]+DIST[from_country][from_city][to_country][to_city]+info[to_country][STATE[to_country]].COST[b]);
					}
				}
			}
		}
	}

	int tmp_ans = BIG_NUM;

	for(int last = 1; last < num_DATA; last++){
		if(DP[POW[num_DATA]-1][last] == BIG_NUM)continue;

		int pre_country = DATA[last].country;
		int pre_city = DATA[last].right;

		int next_country = DATA[0].country;
		int next_city = DATA[0].left;

		if(DIST[pre_country][pre_city][next_country][next_city] == BIG_NUM)continue;

		if(tmp_ans > DP[POW[num_DATA]-1][last]+
				DIST[pre_country][pre_city][next_country][next_city]){
			tmp_ans = DP[POW[num_DATA]-1][last]+
					DIST[pre_country][pre_city][next_country][next_city];
		}
	}

	if(tmp_ans < BIG_NUM){

		ans = min(ans,tmp_ans+add);
	}
}

void calc_dp(int index){

	for(int start = 0; start < num_outer[index]; start++){
		for(int state = 0; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){

				work_dp[start][state][last] = BIG_NUM;
			}
		}
	}

	for(int i = 0; i < num_outer[index]; i++){
		work_dp[i][POW[i]][i] = 0;
		for(int state = 1; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){
				if(work_dp[i][state][last] == BIG_NUM)continue;

				for(int next = 0; next < num_city[index]; next++){
					if(state & POW[next])continue;
					if(DIST[index][last][index][next] == BIG_NUM)continue;

					int next_state = state+POW[next];
					int next_cost = work_dp[i][state][last]+DIST[index][last][index][next];

					work_dp[i][next_state][next] = min(work_dp[i][next_state][next],next_cost);
				}
			}
		}
	}
}

void calc_LAST_NEXT(){

	for(int i = 2; i <= 15; i++){
		int maximum = POW[i];
		num_STATE[i] = 0;
		for(int state = 3; state <= maximum-3; state += 2){ //DATA[0]を訪問済の状態のみ列挙

			table[i][num_STATE[i]++] = state;

			num_NOT[state] = 0;
			for(int k = 1; k < i; k++){
				if(state&POW[k])continue;
				NOT[state][num_NOT[state]++] = k;
			}

			num_LAST[i][state] = 0;

			for(int last = 1; last < i; last++){
				if((state&POW[last]) == 0)continue;

				LAST[i][state][num_LAST[i][state]] = last;
				num_NEXT[i][state][num_LAST[i][state]] = 0;

				for(int next = 1; next < i; next++){
					if(next == last)continue;
					if(state&POW[next])continue;

					NEXT[i][state][num_LAST[i][state]][num_NEXT[i][state][num_LAST[i][state]]++] = next;
				}
				num_LAST[i][state]++;
			}
		}
	}
}

int main(){

	POW[0] = 1;
	for(int i = 1; i <= SIZE; i++){

		POW[i] = POW[i-1]*2;
	}

	for(int a = 0; a < SIZE; a++){
		for(int b = 0; b < SIZE; b++){
			for(int c = 0; c < SIZE; c++){
				for(int d = 0; d < SIZE; d++){
					DIST[a][b][c][d] = BIG_NUM;
				}
			}
		}
	}

	for(int i = 0; i < SIZE; i++){
		for(int a = 0; a < 4; a++){
			for(int b = 0; b < 4; b++){
				pair_used[i][a][b] = false;
				for(int c = 0; c < 4; c++){
					for(int d = 0; d < 4; d++){
						used[i][a][b][c][d] = false;
					}
				}
			}
		}
	}

	scanf("%d %d",&N,&K);

	for(int i = 0; i < N; i++){
		input[i].index = i;
		scanf("%d",&input[i].CITY);
	}

	for(int i = 0; i < N; i++){

		scanf("%d",&input[i].OUTER);
	}

	sort(input,input+N);

	for(int i = 0; i < N; i++){
		MAP[input[i].index] = i;
		num_city[i] = input[i].CITY;
		num_outer[i] = input[i].OUTER;
	}

	int from_country,from_city,to_country,to_city,cost;

	for(int i = 0; i < K; i++){

		scanf("%d %d %d %d %d",&from_country,&from_city,&to_country,&to_city,&cost);
		from_country--;
		from_city--;
		to_country--;
		to_city--;

		from_country = MAP[from_country];
		to_country = MAP[to_country];

		if(from_country == to_country){

			same_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			same_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));

		}else{

			diff_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			diff_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));
		}

		DIST[from_country][from_city][to_country][to_city] = cost;
		DIST[to_country][to_city][from_country][from_city] = cost;
	}

	if(N == 1){

		calc_one();
		return 0;
	}

	calc_LAST_NEXT();
	int start = 0;

	if(num_outer[0] == 4 && num_city[0] > 4){
		calc_dp(0);
		start = 1;
		calc_zero(num_outer[0]);
	}

	for(int i = start; i < N; i++){

		if(num_outer[i] == 1){

			int IN[4] = {0,-1,-1,-1};
			int OUT[4] = {0,-1,-1,-1};
			int COST[3] = {0,-1,-1};
			int L[3];

			if(num_city[i] > 1){

				printf("-1\n");
				return 0;

			}else{

				info[i].push_back(Info(1,IN,OUT,COST,-1,0,L));
			}

		}else if(num_outer[i] == 2){

			calc_dp(i);
			calc_2(i);

		}else if(num_outer[i] == 3){

			calc_dp(i);

			int work_3[3];

			calc_2(i);
			calc_3(i);


		}else{ //num_outer[i] == 4

			calc_dp(i);

			calc_2(i);
			calc_3(i);
			int work_4[4];
			for(int a = 0; a < 4; a++){

				work_4[a] = a;
			}
			calc_4(i,work_4);
		}
	}

	for(int i = 0; i < N; i++){
		if(info[i].size() == 0){

			printf("-1\n");
			return 0;
		}
	}


	ans = BIG_NUM;
	recursive(0);

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}

	return 0;
}
accuracy: 0.2714285714285714
time_ms: 50
memory_kb: 81908
final_rank: 14

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 15
#define NUM 32768

struct Edge{
	Edge(int arg_to_country,int arg_to_city,int arg_cost){
		to_country = arg_to_country;
		to_city = arg_to_city;
		cost = arg_cost;
	}
	int to_country,to_city,cost;
};

struct INPUT{
	bool operator<(const struct INPUT &arg) const{

		if(OUTER != arg.OUTER){
			return OUTER > arg.OUTER;
		}else{
			return CITY > arg.CITY;
		}
	}
	int index,CITY,OUTER;
};

struct Edge2{
	Edge2(int arg_to,int arg_cost){
		to = arg_to;
		cost = arg_cost;
	}
	int to,cost;
};

struct Info{
	Info(int arg_num_out,int arg_IN[4],int arg_OUT[4],int arg_COST[3],int arg_COUNT,int arg_num_L,int arg_L[3]){
		num_out = arg_num_out;
		for(int i = 0; i < num_out; i++){
			IN[i] = arg_IN[i];
			OUT[i] = arg_OUT[i];
		}
		for(int i = 0; i < 3; i++){

			COST[i] = arg_COST[i];
			L[i] = arg_L[i];
		}
		num_L = arg_num_L;
		COUNT = arg_COUNT;
	}
	int num_out,IN[4],OUT[4],COST[3],num_L,L[3],COUNT;
};

struct Data{
	void set(int arg_country,int arg_left,int arg_right){
		country = arg_country;
		left = arg_left;
		right = arg_right;
	}
	int country;
	int left,right;
};

struct DEBUG{

	int pre_state,pre_node;
};

int N,K;
int num_city[SIZE],num_outer[SIZE];
int POW[SIZE+1];
int STATE[SIZE];
int ONE[NUM][SIZE];
int DIST[SIZE][SIZE][SIZE][SIZE];
int work_dp[SIZE][NUM][SIZE];
int DP[NUM][SIZE];
int ans;
int num_STATE[SIZE+1];
int table[SIZE+1][NUM];
int LAST[SIZE+1][NUM][SIZE+1],num_LAST[SIZE+1][NUM];
int NEXT[SIZE+1][NUM][SIZE+1][SIZE+1];
int num_NEXT[SIZE+1][NUM][SIZE+1];
int NOT[NUM][SIZE+1],num_NOT[NUM];
bool used[SIZE][4][4][4][4],pair_used[SIZE][4][4];
Data DATA[SIZE];
vector<Edge> same_G[SIZE][SIZE],diff_G[SIZE][SIZE];
vector<Info> info[SIZE];
map<int,int> MAP;
INPUT input[SIZE+1];


void calc_2(int index){

	if(num_city[index] == 2){ //立ち寄り2回

		int IN[4] = {0,1,-1,-1};
		int OUT[4] = {0,1,-1,-1};
		int COST[3] = {0,-1,-1};
		int L[3];

		info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));

	}else{ //?入りsecond出

		if(index == 0){

			int work[num_outer[index]];
			for(int i = 0; i < num_outer[index]; i++){

				work[i] = i;
			}

			do{

				int first = work[0];
				int second = work[1];
				if(first > second)continue;
				if(work_dp[first][POW[num_city[0]]-1][second] == BIG_NUM)continue;

				int IN[3] = {first,-1,-1};
				int OUT[3] = {second,-1,-1};
				int COST[3] = {work_dp[first][POW[num_city[0]]-1][second],-1,-1};
				int L[3];

				info[0].push_back(Info(1,IN,OUT,COST,-1,0,L));

			}while(next_permutation(work,work+num_outer[index]));

			return;
		}

		for(int second = 0; second < num_outer[index]; second++){
			int num_L = 0;
			int IN[3] = {-1,-1,-1};
			int OUT[3] = {second,-1,-1};
			int COST[3] = {-1,-1,-1};
			int L[3];

			for(int first = 0; first < num_outer[index]; first++){
				if(first == second)continue;
				if(work_dp[first][POW[num_city[index]]-1][second] == BIG_NUM)continue;

				COST[num_L] = work_dp[first][POW[num_city[index]]-1][second];
				L[num_L++] = first;
			}
			if(num_L == 0)continue;
			if(num_L == 1){
				IN[0] = L[0];
				info[index].push_back(Info(1,IN,OUT,COST,-1,0,L));
			}else{
				info[index].push_back(Info(1,IN,OUT,COST,2,num_L,L));
			}
		}
	}
}

void calc_3(int index){

	if(num_outer[index] == 3){

		if(num_city[index] == 3){ //立ち寄り3回

			int IN[4] = {0,1,2,-1};
			int OUT[4] = {0,1,2,-1};
			int COST[3] = {0,-1,-1};
			int L[3];

			info[index].push_back(Info(3,IN,OUT,COST,-1,0,L));

		}else{ //first立ち寄り,second入りthird出

			int work[4] = {0,1,2,3};

			do{
				int first = work[0];
				int second = work[1];
				int third = work[2];
				if(second > third)continue;

				int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

				if(work_dp[second][to_state][third] < BIG_NUM){

					int IN[4] = {first,second,-1,-1};
					int OUT[4] = {first,third,-1,-1};
					int COST[3] = {work_dp[second][to_state][third],-1,-1};
					int L[3];

					info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));
				}

			}while(next_permutation(work,work+3));
		}
	}else{ //num_outer[index] == 4

		for(int first = 0; first < 4; first++){
			for(int third = 0; third < 4; third++){
				if(third == first)continue;

				int IN[4] = {first,-1,-1,-1};
				int OUT[4] = {first,third,-1,-1};
				int COST[3] = {-1,-1,-1};
				int L[3] = {-1,-1,-1};

				int num_L = 0;

				for(int second = 0; second < 4; second++){
					if(second == first || second == third || (index == 0 && second >third))continue;

					int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

					if(work_dp[second][to_state][third] < BIG_NUM){

						COST[num_L] = work_dp[second][to_state][third];
						L[num_L++] = second;
					}
				}
				if(num_L == 0)continue;
				if(num_L == 1){

					IN[1] = L[0];
					info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));
				}else{

					info[index].push_back(Info(2,IN,OUT,COST,3,num_L,L));
				}
			}
		}
	}
}

void calc_4(int index,int work[4]){

	int L[3];

	if(num_city[index] == 4){ //立ち寄り4回

		int IN[4] = {work[0],work[1],work[2],work[3]};
		int OUT[4] = {work[0],work[1],work[2],work[3]};
		int COST[3] = {0,-1,-1};

		info[index].push_back(Info(4,IN,OUT,COST,-1,0,L));

	}else{

		do{

			int a = work[0];
			int b = work[1];
			int c = work[2];
			int d = work[3];

			//a入りb出-c入d出
			if(!used[index][c][d][a][b]){
				used[index][a][b][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[c]+POW[d]);
				int tmp_cost = BIG_NUM;

				for(int from_state = 1; from_state <= to_state; from_state++){
					if(((from_state & POW[c]) == POW[c]) ||
						((from_state & POW[d]) == POW[d]) ||
						((from_state & POW[a]) != POW[a]) ||
						((from_state & POW[b]) != POW[b]))continue;
					if(work_dp[a][from_state][b] == BIG_NUM)continue;

					int rest_state = POW[num_city[index]]-1-from_state;
					if(work_dp[c][rest_state][d] == BIG_NUM)continue;

					tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
				}

				if(tmp_cost < BIG_NUM){

					int IN[4] = {a,c,-1,-1};
					int OUT[4] = {b,d,-1,-1};
					int COST[3] = {tmp_cost,-1,-1};

					info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));
				}
			}

			//a,b立ち寄り,c入d出
			if(!pair_used[index][c][d]){
				pair_used[index][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[a]+POW[b]);

				if(work_dp[c][to_state][d] < BIG_NUM){

					int IN[4] = {a,b,c,-1};
					int OUT[4] = {a,b,d,-1};
					int COST[3] = {work_dp[c][to_state][d],-1,-1};

					info[index].push_back(Info(3,IN,OUT,COST,-1,0,L));
				}
			}

		}while(next_permutation(work,work+4));
	}
}

void calc_zero(int count_outer){

	int L[3];

	for(int left = 0; left <= 2; left++){
		int IN[4] = {left,-1,-1,-1};
		int OUT[4] = {-1,-1,-1,-1};

		int COST[3];
		for(int i = 0; i < 3; i++){

			COST[i] = -1;
		}
		for(int right = left+1; right <= 3; right++){

			COST[right-(left+1)] = work_dp[left][POW[num_city[0]]-1][right]; //left入りright出
		}

		info[0].push_back(Info(1,IN,OUT,COST,2,0,L));
	}

	int first,second,third;

	int work[4] = {0,1,2,3};

	do{
		first = work[0];
		second = work[1];
		third = work[2];
		if(second > third)continue;

		int to_state = (POW[num_city[0]]-1)-POW[first]; //firstを除いてTSP

		if(work_dp[second][to_state][third] < BIG_NUM){

			int IN[4] = {first,second,-1,-1};
			int OUT[4] = {first,third,-1,-1};
			int COST[3] = {work_dp[second][to_state][third],-1,-1};

			info[0].push_back(Info(2,IN,OUT,COST,-1,0,L));
		}

	}while(next_permutation(work,work+4));

	int a,b,c,d;
	for(int loop = 0; loop < 6; loop++){
		if(loop == 0){
			a = 0;
			b = 1;
			c = 2;
			d = 3;
		}else if(loop == 1){
			a = 0;
			b = 1;
			c = 3;
			d = 2;
		}else if(loop == 2){
			a = 0;
			b = 2;
			c = 1;
			d = 3;
		}else if(loop == 3){
			a = 0;
			b = 2;
			c = 3;
			d = 1;
		}else if(loop == 4){
			a = 0;
			b = 3;
			c = 1;
			d = 2;
		}else{ //loop == 5
			a = 0;
			b = 3;
			c = 2;
			d = 1;
		}

		//a入りb出-c入d出
		int to_state = (POW[num_city[0]]-1)-(POW[c]+POW[d]);
		int tmp_cost = BIG_NUM;

		for(int from_state = 1; from_state <= to_state; from_state++){
			if(((from_state & POW[c]) == POW[c]) ||
				((from_state & POW[d]) == POW[d]) ||
				((from_state & POW[a]) != POW[a]) ||
				((from_state & POW[b]) != POW[b]))continue;
			if(work_dp[a][from_state][b] == BIG_NUM)continue;

			int rest_state = POW[num_city[0]]-1-from_state;
			if(work_dp[c][rest_state][d] == BIG_NUM)continue;

			tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
		}

		if(tmp_cost < BIG_NUM){

			int IN[4] = {a,c,-1,-1};
			int OUT[4] = {b,d,-1,-1};
			int COST[3] = {tmp_cost,-1,-1};

			info[0].push_back(Info(2,IN,OUT,COST,-1,0,L));
		}
	}

	for(int loop = 0; loop < 6; loop++){
		if(loop == 0){
			a = 2;
			b = 3;
			c = 0;
			d = 1;
		}else if(loop == 1){
			a = 1;
			b = 3;
			c = 0;
			d = 2;
		}else if(loop == 2){
			a = 1;
			b = 2;
			c = 0;
			d = 3;
		}else if(loop == 3){
			a = 0;
			b = 3;
			c = 1;
			d = 2;
		}else if(loop == 4){
			a = 0;
			b = 2;
			c = 1;
			d = 3;
		}else{ //loop == 5
			a = 0;
			b = 1;
			c = 2;
			d = 3;
		}

		//a,b立ち寄り,c入d出
		int to_state = (POW[num_city[0]]-1)-(POW[a]+POW[b]);

		if(work_dp[c][to_state][d] < BIG_NUM){

			int IN[4] = {a,b,c,-1};
			int OUT[4] = {a,b,d,-1};
			int COST[3] = {work_dp[c][to_state][d],-1,-1};
			info[0].push_back(Info(3,IN,OUT,COST,-1,0,L));
		}
	}
}

void calc_one(){

	if(num_city[0] == 1){

		printf("0\n");
		return;
	}

	int index = 0;

	for(int state = 0; state < POW[num_city[index]]; state++){
		for(int last = 0; last < num_city[index]; last++){

			ONE[state][last] = BIG_NUM;
		}
	}

	//経路は輪になるので、スタートは0として良いはず
	ONE[POW[0]][0] = 0;

	for(int state = 1; state < POW[num_city[index]]-1; state++){
		for(int last = 0; last < num_city[index]; last++){
			if(ONE[state][last] == BIG_NUM)continue;

			for(int i = 0; i < same_G[index][last].size(); i++){

				int next_node = same_G[index][last][i].to_city;

				if(state & POW[next_node])continue;

				int next_state = state+POW[next_node];
				int next_cost = ONE[state][last]+same_G[index][last][i].cost;

				ONE[next_state][next_node] = min(ONE[next_state][next_node],next_cost);
			}
		}
	}

	int ans = BIG_NUM;
	for(int last = 0; last < num_city[index]; last++){
		if(ONE[POW[num_city[index]]-1][last] == BIG_NUM)continue;

		ans = min(ans,ONE[POW[num_city[index]]-1][last]+DIST[0][last][0][0]);
	}

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}
}
void recursive(int index){

	if(index < N){

		for(int i = 0; i < info[index].size(); i++){

			STATE[index] = i;
			recursive(index+1);
		}
		return;
	}

	//index == N
	int num_DATA = 0;
	int add = 0;

	int work_DIST[SIZE][SIZE];
	for(int i = 0; i < SIZE; i++){
		for(int k = 0; k < SIZE; k++){

			work_DIST[i][k] = BIG_NUM;
		}
	}

	for(int i = 0; i < N; i++){
		int num = STATE[i];
		if(info[i][num].COUNT == -1){
			add += info[i][num].COST[0];
		}
		for(int k = 0; k < info[i][num].num_out; k++){

			DATA[num_DATA++].set(i,info[i][num].IN[k],info[i][STATE[i]].OUT[k]);
		}
	}

	if(add >= ans)return;

	for(int i = 1; i < num_DATA; i++){
		for(int k = 1; k < num_DATA; k++){
			if((k == i)||(num_city[DATA[i].country] < num_outer[DATA[i].country] && DATA[i].country == DATA[k].country))continue;
			if(DATA[k].left == -1)continue;

			int from_country = DATA[i].country;
			int from_city = DATA[i].right;

			int to_country = DATA[k].country;
			int to_city = DATA[k].left;

			if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

			work_DIST[i][k] = DIST[from_country][from_city][to_country][to_city];
		}
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		int state = table[num_DATA][i];
		for(int k = 0; k < num_LAST[num_DATA][state]; k++){

			DP[state][LAST[num_DATA][state][k]] = BIG_NUM;
		}
	}
	for(int last = 1; last < num_DATA; last++){

		DP[POW[num_DATA]-1][last] = BIG_NUM;
	}

	for(int k = 1; k < num_DATA; k++){
		if(info[0][STATE[0]].COUNT == -1){ //国0がnum2でない
				int from_country = 0;
				int from_city = DATA[0].right;

				if(DATA[k].left != -1){

					int to_country = DATA[k].country;
					int to_city = DATA[k].left;

					if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

					DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],DIST[from_country][from_city][to_country][to_city]);
				}else{

					int to_country = DATA[k].country;
					for(int a = 0; a < info[to_country][STATE[to_country]].num_L; a++){

						int to_city = info[to_country][STATE[to_country]].L[a];

						if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

						DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],
								DIST[from_country][from_city][to_country][to_city]+info[to_country][STATE[to_country]].COST[a]);
					}
				}

		}else{ //国0がnum2

			int left = DATA[0].left;

			for(int right = left+1; right <= 3; right++){

				int from_country = 0;
				int from_city = right;

				if(DATA[k].left != -1){

					int to_country = DATA[k].country;
					int to_city = DATA[k].left;

					if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;
					int tmp_cost = info[0][STATE[0]].COST[right-(left+1)];
					if(tmp_cost == BIG_NUM)continue;

					DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],DIST[from_country][from_city][to_country][to_city]+tmp_cost);
				}else{

					int tmp_cost = info[0][STATE[0]].COST[right-(left+1)];
					if(tmp_cost == BIG_NUM)continue;

					int to_country = DATA[k].country;
					for(int a = 0; a < info[to_country][STATE[to_country]].num_L; a++){

						int to_city = info[to_country][STATE[to_country]].L[a];
						if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

						DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],
								DIST[from_country][from_city][to_country][to_city]+info[to_country][STATE[to_country]].COST[a]+tmp_cost);
					}
				}
			}
		}
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		int state = table[num_DATA][i];
		int max_k = num_LAST[num_DATA][state];
		for(int k = 0; k < max_k; k++){
			int last = LAST[num_DATA][state][k];
			if(DP[state][last]==BIG_NUM)continue;
			int max_a = num_NEXT[num_DATA][state][k];
			for(int a = 0; a < max_a; a++){
				int next = NEXT[num_DATA][state][k][a];
				if(DATA[next].left != -1){
					DP[state|(1<<next)][next] = min(DP[state|(1<<next)][next],DP[state][last]+work_DIST[last][next]);
				}else{

					int from_country = DATA[last].country;
					int from_city = DATA[last].right;

					int to_country = DATA[next].country;
					int max_b = info[to_country][STATE[to_country]].num_L;

					for(int b = 0; b < max_b; b++){
						int to_city = info[to_country][STATE[to_country]].L[b];
						if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

						DP[state|(1<<next)][next] = min(DP[state|(1<<next)][next],
								DP[state][last]+DIST[from_country][from_city][to_country][to_city]+info[to_country][STATE[to_country]].COST[b]);
					}
				}
			}
		}
	}

	int tmp_ans = BIG_NUM;

	for(int last = 1; last < num_DATA; last++){
		if(DP[POW[num_DATA]-1][last] == BIG_NUM)continue;

		int pre_country = DATA[last].country;
		int pre_city = DATA[last].right;

		int next_country = DATA[0].country;
		int next_city = DATA[0].left;

		if(DIST[pre_country][pre_city][next_country][next_city] == BIG_NUM)continue;

		if(tmp_ans > DP[POW[num_DATA]-1][last]+
				DIST[pre_country][pre_city][next_country][next_city]){
			tmp_ans = DP[POW[num_DATA]-1][last]+
					DIST[pre_country][pre_city][next_country][next_city];
		}
	}

	if(tmp_ans < BIG_NUM){

		ans = min(ans,tmp_ans+add);
	}
}

void calc_dp(int index){

	for(int start = 0; start < num_outer[index]; start++){
		for(int state = 0; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){

				work_dp[start][state][last] = BIG_NUM;
			}
		}
	}

	for(int i = 0; i < num_outer[index]; i++){
		work_dp[i][POW[i]][i] = 0;
		for(int state = 1; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){
				if(work_dp[i][state][last] == BIG_NUM)continue;

				for(int next = 0; next < num_city[index]; next++){
					if(state & POW[next])continue;
					if(DIST[index][last][index][next] == BIG_NUM)continue;

					int next_state = state+POW[next];
					int next_cost = work_dp[i][state][last]+DIST[index][last][index][next];

					work_dp[i][next_state][next] = min(work_dp[i][next_state][next],next_cost);
				}
			}
		}
	}
}

void calc_LAST_NEXT(){

	for(int i = 2; i <= 15; i++){
		int maximum = POW[i];
		num_STATE[i] = 0;
		for(int state = 3; state <= maximum-3; state += 2){ //DATA[0]を訪問済の状態のみ列挙

			table[i][num_STATE[i]++] = state;

			num_NOT[state] = 0;
			for(int k = 1; k < i; k++){
				if(state&POW[k])continue;
				NOT[state][num_NOT[state]++] = k;
			}

			num_LAST[i][state] = 0;

			for(int last = 1; last < i; last++){
				if((state&POW[last]) == 0)continue;

				LAST[i][state][num_LAST[i][state]] = last;
				num_NEXT[i][state][num_LAST[i][state]] = 0;

				for(int next = 1; next < i; next++){
					if(next == last)continue;
					if(state&POW[next])continue;

					NEXT[i][state][num_LAST[i][state]][num_NEXT[i][state][num_LAST[i][state]]++] = next;
				}
				num_LAST[i][state]++;
			}
		}
	}
}

int main(){

	POW[0] = 1;
	for(int i = 1; i <= SIZE; i++){

		POW[i] = POW[i-1]*2;
	}

	for(int a = 0; a < SIZE; a++){
		for(int b = 0; b < SIZE; b++){
			for(int c = 0; c < SIZE; c++){
				for(int d = 0; d < SIZE; d++){
					DIST[a][b][c][d] = BIG_NUM;
				}
			}
		}
	}

	for(int i = 0; i < SIZE; i++){
		for(int a = 0; a < 4; a++){
			for(int b = 0; b < 4; b++){
				pair_used[i][a][b] = false;
				for(int c = 0; c < 4; c++){
					for(int d = 0; d < 4; d++){
						used[i][a][b][c][d] = false;
					}
				}
			}
		}
	}

	scanf("%d %d",&N,&K);

	for(int i = 0; i < N; i++){
		input[i].index = i;
		scanf("%d",&input[i].CITY);
	}

	for(int i = 0; i < N; i++){

		scanf("%d",&input[i].OUTER);
	}

	sort(input,input+N);

	for(int i = 0; i < N; i++){
		MAP[input[i].index] = i;
		num_city[i] = input[i].CITY;
		num_outer[i] = input[i].OUTER;
	}

	int from_country,from_city,to_country,to_city,cost;

	for(int i = 0; i < K; i++){

		scanf("%d %d %d %d %d",&from_country,&from_city,&to_country,&to_city,&cost);
		from_country--;
		from_city--;
		to_country--;
		to_city--;

		from_country = MAP[from_country];
		to_country = MAP[to_country];

		if(from_country == to_country){

			same_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			same_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));

		}else{

			diff_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			diff_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));
		}

		DIST[from_country][from_city][to_country][to_city] = cost;
		DIST[to_country][to_city][from_country][from_city] = cost;
	}

	if(N == 1){

		calc_one();
		return 0;
	}

	calc_LAST_NEXT();
	int start = 0;

	if(num_outer[0] == 4 && num_city[0] > 4){
		calc_dp(0);
		start = 1;
		calc_zero(num_outer[0]);
	}

	for(int i = start; i < N; i++){

		if(num_outer[i] == 1){

			int IN[4] = {0,-1,-1,-1};
			int OUT[4] = {0,-1,-1,-1};
			int COST[3] = {0,-1,-1};
			int L[3];

			if(num_city[i] > 1){

				printf("-1\n");
				return 0;

			}else{

				info[i].push_back(Info(1,IN,OUT,COST,-1,0,L));
			}

		}else if(num_outer[i] == 2){

			calc_dp(i);
			calc_2(i);

		}else if(num_outer[i] == 3){

			calc_dp(i);

			int work_3[3];

			calc_2(i);
			calc_3(i);


		}else{ //num_outer[i] == 4

			calc_dp(i);

			calc_2(i);
			calc_3(i);
			int work_4[4];
			for(int a = 0; a < 4; a++){

				work_4[a] = a;
			}
			calc_4(i,work_4);
		}
	}

	for(int i = 0; i < N; i++){
		if(info[i].size() == 0){

			printf("-1\n");
			return 0;
		}
	}


	ans = BIG_NUM;
	recursive(0);

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}

	return 0;
}
accuracy: 0.05714285714285714
time_ms: 20
memory_kb: 79940
final_rank: 16

code_snippet: #include<bits/stdc++.h>
/*m(_ _)m申し訳ございません*/
#pragma GCC target("avx")
#pragma GCC optimize("O3")
/*m(_ _)m申し訳ございません*/
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 15
#define NUM 32768

struct Edge{
	Edge(int arg_to_country,int arg_to_city,int arg_cost){
		to_country = arg_to_country;
		to_city = arg_to_city;
		cost = arg_cost;
	}
	int to_country,to_city,cost;
};

struct INPUT{
	bool operator<(const struct INPUT &arg) const{

		if(OUTER != arg.OUTER){
			return OUTER > arg.OUTER;
		}else{
			return CITY > arg.CITY;
		}
	}
	int index,CITY,OUTER;
};

struct Edge2{
	Edge2(int arg_to,int arg_cost){
		to = arg_to;
		cost = arg_cost;
	}
	int to,cost;
};

struct Info{
	Info(int arg_num_out,int arg_IN[4],int arg_OUT[4],int arg_COST[3],int arg_COUNT,int arg_num_L,int arg_L[3]){
		num_out = arg_num_out;
		for(int i = 0; i < num_out; i++){
			IN[i] = arg_IN[i];
			OUT[i] = arg_OUT[i];
		}
		for(int i = 0; i < 3; i++){

			COST[i] = arg_COST[i];
			L[i] = arg_L[i];
		}
		num_L = arg_num_L;
		COUNT = arg_COUNT;
	}
	int num_out,IN[4],OUT[4],COST[3],num_L,L[3],COUNT;
};

struct Data{
	void set(int arg_country,int arg_left,int arg_right){
		country = arg_country;
		left = arg_left;
		right = arg_right;
	}
	int country;
	int left,right;
};

struct DEBUG{

	int pre_state,pre_node;
};

int N,K;
int num_city[SIZE],num_outer[SIZE];
int POW[SIZE+1];
int STATE[SIZE];
int ONE[NUM][SIZE];
int DIST[SIZE][SIZE][SIZE][SIZE];
int work_dp[SIZE][NUM][SIZE];
int DP[NUM][SIZE];
int ans;
int num_STATE[SIZE+1];
int table[SIZE+1][NUM];
int LAST[SIZE+1][NUM][SIZE+1],num_LAST[SIZE+1][NUM];
int NEXT[SIZE+1][NUM][SIZE+1][SIZE+1];
int num_NEXT[SIZE+1][NUM][SIZE+1];
int NOT[NUM][SIZE+1],num_NOT[NUM];
bool used[SIZE][4][4][4][4],pair_used[SIZE][4][4];
Data DATA[SIZE];
vector<Edge> same_G[SIZE][SIZE],diff_G[SIZE][SIZE];
vector<Info> info[SIZE];
map<int,int> MAP;
INPUT input[SIZE+1];


void calc_2(int index){

	if(num_city[index] == 2){ //立ち寄り2回

		int IN[4] = {0,1,-1,-1};
		int OUT[4] = {0,1,-1,-1};
		int COST[3] = {0,-1,-1};
		int L[3];

		info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));

	}else{ //?入りsecond出

		if(index == 0){

			int work[num_outer[index]];
			for(int i = 0; i < num_outer[index]; i++){

				work[i] = i;
			}

			do{

				int first = work[0];
				int second = work[1];
				if(first > second)continue;
				if(work_dp[first][POW[num_city[0]]-1][second] == BIG_NUM)continue;

				int IN[3] = {first,-1,-1};
				int OUT[3] = {second,-1,-1};
				int COST[3] = {work_dp[first][POW[num_city[0]]-1][second],-1,-1};
				int L[3];

				info[0].push_back(Info(1,IN,OUT,COST,-1,0,L));

			}while(next_permutation(work,work+num_outer[index]));

			return;
		}

		for(int second = 0; second < num_outer[index]; second++){
			int num_L = 0;
			int IN[3] = {-1,-1,-1};
			int OUT[3] = {second,-1,-1};
			int COST[3] = {-1,-1,-1};
			int L[3];

			for(int first = 0; first < num_outer[index]; first++){
				if(first == second)continue;
				if(work_dp[first][POW[num_city[index]]-1][second] == BIG_NUM)continue;

				COST[num_L] = work_dp[first][POW[num_city[index]]-1][second];
				L[num_L++] = first;
			}
			if(num_L == 0)continue;
			if(num_L == 1){
				IN[0] = L[0];
				info[index].push_back(Info(1,IN,OUT,COST,-1,0,L));
			}else{
				info[index].push_back(Info(1,IN,OUT,COST,2,num_L,L));
			}
		}
	}
}

void calc_3(int index,int work[3]){

	int L[3];

	if(num_city[index] == 3){ //立ち寄り3回

		int IN[4] = {work[0],work[1],work[2],-1};
		int OUT[4] = {work[0],work[1],work[2],-1};
		int COST[3] = {0,-1,-1};

		info[index].push_back(Info(3,IN,OUT,COST,-1,0,L));

	}else{ //first立ち寄り,second入りthird出

		do{
			int first = work[0];
			int second = work[1];
			int third = work[2];

			int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

			if(work_dp[second][to_state][third] < BIG_NUM){

				int IN[4] = {first,second,-1,-1};
				int OUT[4] = {first,third,-1,-1};
				int COST[3] = {work_dp[second][to_state][third],-1,-1};

				info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));
			}

		}while(next_permutation(work,work+3));
	}
}

void calc_4(int index,int work[4]){

	int L[3];

	if(num_city[index] == 4){ //立ち寄り4回

		int IN[4] = {work[0],work[1],work[2],work[3]};
		int OUT[4] = {work[0],work[1],work[2],work[3]};
		int COST[3] = {0,-1,-1};

		info[index].push_back(Info(4,IN,OUT,COST,-1,0,L));

	}else{

		do{

			int a = work[0];
			int b = work[1];
			int c = work[2];
			int d = work[3];

			//a入りb出-c入d出
			if(!used[index][c][d][a][b]){
				used[index][a][b][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[c]+POW[d]);
				int tmp_cost = BIG_NUM;

				for(int from_state = 1; from_state <= to_state; from_state++){
					if(((from_state & POW[c]) == POW[c]) ||
						((from_state & POW[d]) == POW[d]) ||
						((from_state & POW[a]) != POW[a]) ||
						((from_state & POW[b]) != POW[b]))continue;
					if(work_dp[a][from_state][b] == BIG_NUM)continue;

					int rest_state = POW[num_city[index]]-1-from_state;
					if(work_dp[c][rest_state][d] == BIG_NUM)continue;

					tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
				}

				if(tmp_cost < BIG_NUM){

					int IN[4] = {a,c,-1,-1};
					int OUT[4] = {b,d,-1,-1};
					int COST[3] = {tmp_cost,-1,-1};

					info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));
				}
			}

			//a,b立ち寄り,c入d出
			if(!pair_used[index][c][d]){
				pair_used[index][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[a]+POW[b]);

				if(work_dp[c][to_state][d] < BIG_NUM){

					int IN[4] = {a,b,c,-1};
					int OUT[4] = {a,b,d,-1};
					int COST[3] = {work_dp[c][to_state][d],-1,-1};

					info[index].push_back(Info(3,IN,OUT,COST,-1,0,L));
				}
			}

		}while(next_permutation(work,work+4));
	}
}

void calc_zero(int count_outer){

	int L[3];

	for(int left = 0; left <= 2; left++){
		int IN[4] = {left,-1,-1,-1};
		int OUT[4] = {-1,-1,-1,-1};

		int COST[3];
		for(int i = 0; i < 3; i++){

			COST[i] = -1;
		}
		for(int right = left+1; right <= 3; right++){

			COST[right-(left+1)] = work_dp[left][POW[num_city[0]]-1][right]; //left入りright出
		}

		info[0].push_back(Info(1,IN,OUT,COST,2,0,L));
	}

	int first,second,third;

	int work[4] = {0,1,2,3};

	do{
		first = work[0];
		second = work[1];
		third = work[2];
		if(second > third)continue;

		int to_state = (POW[num_city[0]]-1)-POW[first]; //firstを除いてTSP

		if(work_dp[second][to_state][third] < BIG_NUM){

			int IN[4] = {first,second,-1,-1};
			int OUT[4] = {first,third,-1,-1};
			int COST[3] = {work_dp[second][to_state][third],-1,-1};

			info[0].push_back(Info(2,IN,OUT,COST,-1,0,L));
		}

	}while(next_permutation(work,work+4));

	int a,b,c,d;
	for(int loop = 0; loop < 6; loop++){
		if(loop == 0){
			a = 0;
			b = 1;
			c = 2;
			d = 3;
		}else if(loop == 1){
			a = 0;
			b = 1;
			c = 3;
			d = 2;
		}else if(loop == 2){
			a = 0;
			b = 2;
			c = 1;
			d = 3;
		}else if(loop == 3){
			a = 0;
			b = 2;
			c = 3;
			d = 1;
		}else if(loop == 4){
			a = 0;
			b = 3;
			c = 1;
			d = 2;
		}else{ //loop == 5
			a = 0;
			b = 3;
			c = 2;
			d = 1;
		}

		//a入りb出-c入d出
		int to_state = (POW[num_city[0]]-1)-(POW[c]+POW[d]);
		int tmp_cost = BIG_NUM;

		for(int from_state = 1; from_state <= to_state; from_state++){
			if(((from_state & POW[c]) == POW[c]) ||
				((from_state & POW[d]) == POW[d]) ||
				((from_state & POW[a]) != POW[a]) ||
				((from_state & POW[b]) != POW[b]))continue;
			if(work_dp[a][from_state][b] == BIG_NUM)continue;

			int rest_state = POW[num_city[0]]-1-from_state;
			if(work_dp[c][rest_state][d] == BIG_NUM)continue;

			tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
		}

		if(tmp_cost < BIG_NUM){

			int IN[4] = {a,c,-1,-1};
			int OUT[4] = {b,d,-1,-1};
			int COST[3] = {tmp_cost,-1,-1};

			info[0].push_back(Info(2,IN,OUT,COST,-1,0,L));
		}
	}

	for(int loop = 0; loop < 6; loop++){
		if(loop == 0){
			a = 2;
			b = 3;
			c = 0;
			d = 1;
		}else if(loop == 1){
			a = 1;
			b = 3;
			c = 0;
			d = 2;
		}else if(loop == 2){
			a = 1;
			b = 2;
			c = 0;
			d = 3;
		}else if(loop == 3){
			a = 0;
			b = 3;
			c = 1;
			d = 2;
		}else if(loop == 4){
			a = 0;
			b = 2;
			c = 1;
			d = 3;
		}else{ //loop == 5
			a = 0;
			b = 1;
			c = 2;
			d = 3;
		}

		//a,b立ち寄り,c入d出
		int to_state = (POW[num_city[0]]-1)-(POW[a]+POW[b]);

		if(work_dp[c][to_state][d] < BIG_NUM){

			int IN[4] = {a,b,c,-1};
			int OUT[4] = {a,b,d,-1};
			int COST[3] = {work_dp[c][to_state][d],-1,-1};
			info[0].push_back(Info(3,IN,OUT,COST,-1,0,L));
		}
	}
}

void calc_one(){

	if(num_city[0] == 1){

		printf("0\n");
		return;
	}

	int index = 0;

	for(int state = 0; state < POW[num_city[index]]; state++){
		for(int last = 0; last < num_city[index]; last++){

			ONE[state][last] = BIG_NUM;
		}
	}

	//経路は輪になるので、スタートは0として良いはず
	ONE[POW[0]][0] = 0;

	for(int state = 1; state < POW[num_city[index]]-1; state++){
		for(int last = 0; last < num_city[index]; last++){
			if(ONE[state][last] == BIG_NUM)continue;

			for(int i = 0; i < same_G[index][last].size(); i++){

				int next_node = same_G[index][last][i].to_city;

				if(state & POW[next_node])continue;

				int next_state = state+POW[next_node];
				int next_cost = ONE[state][last]+same_G[index][last][i].cost;

				ONE[next_state][next_node] = min(ONE[next_state][next_node],next_cost);
			}
		}
	}

	int ans = BIG_NUM;
	for(int last = 0; last < num_city[index]; last++){
		if(ONE[POW[num_city[index]]-1][last] == BIG_NUM)continue;

		ans = min(ans,ONE[POW[num_city[index]]-1][last]+DIST[0][last][0][0]);
	}

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}
}
void recursive(int index){

	if(index < N){

		for(int i = 0; i < info[index].size(); i++){

			STATE[index] = i;
			recursive(index+1);
		}
		return;
	}

	//index == N
	int num_DATA = 0;
	int add = 0;

	int work_DIST[SIZE][SIZE];
	for(int i = 0; i < SIZE; i++){
		for(int k = 0; k < SIZE; k++){

			work_DIST[i][k] = BIG_NUM;
		}
	}

	for(int i = 0; i < N; i++){
		int num = STATE[i];
		if(info[i][num].COUNT == -1){
			add += info[i][num].COST[0];
		}
		for(int k = 0; k < info[i][num].num_out; k++){

			DATA[num_DATA++].set(i,info[i][num].IN[k],info[i][STATE[i]].OUT[k]);
		}
	}

	if(add >= ans)return;

	for(int i = 1; i < num_DATA; i++){
		for(int k = 1; k < num_DATA; k++){
			if((k == i)||(num_city[DATA[i].country] < num_outer[DATA[i].country] && DATA[i].country == DATA[k].country))continue;
			if(DATA[k].left == -1)continue;

			int from_country = DATA[i].country;
			int from_city = DATA[i].right;

			int to_country = DATA[k].country;
			int to_city = DATA[k].left;

			if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

			work_DIST[i][k] = DIST[from_country][from_city][to_country][to_city];
		}
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		int state = table[num_DATA][i];
		for(int k = 0; k < num_LAST[num_DATA][state]; k++){

			DP[state][LAST[num_DATA][state][k]] = BIG_NUM;
		}
	}
	for(int last = 1; last < num_DATA; last++){

		DP[POW[num_DATA]-1][last] = BIG_NUM;
	}

	for(int k = 1; k < num_DATA; k++){
		if(info[0][STATE[0]].COUNT == -1){ //国0がnum2でない
				int from_country = 0;
				int from_city = DATA[0].right;

				if(DATA[k].left != -1){

					int to_country = DATA[k].country;
					int to_city = DATA[k].left;

					if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

					DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],DIST[from_country][from_city][to_country][to_city]);
				}else{

					int to_country = DATA[k].country;
					for(int a = 0; a < info[to_country][STATE[to_country]].num_L; a++){

						int to_city = info[to_country][STATE[to_country]].L[a];

						if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

						DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],
								DIST[from_country][from_city][to_country][to_city]+info[to_country][STATE[to_country]].COST[a]);
					}
				}

		}else{ //国0がnum2

			int left = DATA[0].left;

			for(int right = left+1; right <= 3; right++){

				int from_country = 0;
				int from_city = right;

				if(DATA[k].left != -1){

					int to_country = DATA[k].country;
					int to_city = DATA[k].left;

					if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;
					int tmp_cost = info[0][STATE[0]].COST[right-(left+1)];
					if(tmp_cost == BIG_NUM)continue;

					DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],DIST[from_country][from_city][to_country][to_city]+tmp_cost);
				}else{

					int tmp_cost = info[0][STATE[0]].COST[right-(left+1)];
					if(tmp_cost == BIG_NUM)continue;

					int to_country = DATA[k].country;
					for(int a = 0; a < info[to_country][STATE[to_country]].num_L; a++){

						int to_city = info[to_country][STATE[to_country]].L[a];
						if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

						DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],
								DIST[from_country][from_city][to_country][to_city]+info[to_country][STATE[to_country]].COST[a]+tmp_cost);
					}
				}
			}
		}
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		int state = table[num_DATA][i];
		int max_k = num_LAST[num_DATA][state];
		for(int k = 0; k < max_k; k++){
			int last = LAST[num_DATA][state][k];
			if(DP[state][last]==BIG_NUM)continue;
			int max_a = num_NEXT[num_DATA][state][k];
			for(int a = 0; a < max_a; a++){
				int next = NEXT[num_DATA][state][k][a];
				if(DATA[next].left != -1){
					DP[state|(1<<next)][next] = min(DP[state|(1<<next)][next],DP[state][last]+work_DIST[last][next]);
				}else{

					int from_country = DATA[last].country;
					int from_city = DATA[last].right;

					int to_country = DATA[next].country;
					int max_b = info[to_country][STATE[to_country]].num_L;

					for(int b = 0; b < max_b; b++){
						int to_city = info[to_country][STATE[to_country]].L[b];
						if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

						DP[state|(1<<next)][next] = min(DP[state|(1<<next)][next],
								DP[state][last]+DIST[from_country][from_city][to_country][to_city]+info[to_country][STATE[to_country]].COST[b]);
					}
				}
			}
		}
	}

	int tmp_ans = BIG_NUM;

	for(int last = 1; last < num_DATA; last++){
		if(DP[POW[num_DATA]-1][last] == BIG_NUM)continue;

		int pre_country = DATA[last].country;
		int pre_city = DATA[last].right;

		int next_country = DATA[0].country;
		int next_city = DATA[0].left;

		if(DIST[pre_country][pre_city][next_country][next_city] == BIG_NUM)continue;

		if(tmp_ans > DP[POW[num_DATA]-1][last]+
				DIST[pre_country][pre_city][next_country][next_city]){
			tmp_ans = DP[POW[num_DATA]-1][last]+
					DIST[pre_country][pre_city][next_country][next_city];
		}
	}

	if(tmp_ans < BIG_NUM){

		ans = min(ans,tmp_ans+add);
	}
}

void calc_dp(int index){

	for(int start = 0; start < num_outer[index]; start++){
		for(int state = 0; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){

				work_dp[start][state][last] = BIG_NUM;
			}
		}
	}

	for(int i = 0; i < num_outer[index]; i++){
		work_dp[i][POW[i]][i] = 0;
		for(int state = 1; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){
				if(work_dp[i][state][last] == BIG_NUM)continue;

				for(int next = 0; next < num_city[index]; next++){
					if(state & POW[next])continue;
					if(DIST[index][last][index][next] == BIG_NUM)continue;

					int next_state = state+POW[next];
					int next_cost = work_dp[i][state][last]+DIST[index][last][index][next];

					work_dp[i][next_state][next] = min(work_dp[i][next_state][next],next_cost);
				}
			}
		}
	}
}

void calc_LAST_NEXT(){

	for(int i = 2; i <= 15; i++){
		int maximum = POW[i];
		num_STATE[i] = 0;
		for(int state = 3; state <= maximum-3; state += 2){ //DATA[0]を訪問済の状態のみ列挙

			table[i][num_STATE[i]++] = state;

			num_NOT[state] = 0;
			for(int k = 1; k < i; k++){
				if(state&POW[k])continue;
				NOT[state][num_NOT[state]++] = k;
			}

			num_LAST[i][state] = 0;

			for(int last = 1; last < i; last++){
				if((state&POW[last]) == 0)continue;

				LAST[i][state][num_LAST[i][state]] = last;
				num_NEXT[i][state][num_LAST[i][state]] = 0;

				for(int next = 1; next < i; next++){
					if(next == last)continue;
					if(state&POW[next])continue;

					NEXT[i][state][num_LAST[i][state]][num_NEXT[i][state][num_LAST[i][state]]++] = next;
				}
				num_LAST[i][state]++;
			}
		}
	}
}

int main(){

	POW[0] = 1;
	for(int i = 1; i <= SIZE; i++){

		POW[i] = POW[i-1]*2;
	}

	for(int a = 0; a < SIZE; a++){
		for(int b = 0; b < SIZE; b++){
			for(int c = 0; c < SIZE; c++){
				for(int d = 0; d < SIZE; d++){
					DIST[a][b][c][d] = BIG_NUM;
				}
			}
		}
	}

	for(int i = 0; i < SIZE; i++){
		for(int a = 0; a < 4; a++){
			for(int b = 0; b < 4; b++){
				pair_used[i][a][b] = false;
				for(int c = 0; c < 4; c++){
					for(int d = 0; d < 4; d++){
						used[i][a][b][c][d] = false;
					}
				}
			}
		}
	}

	scanf("%d %d",&N,&K);

	for(int i = 0; i < N; i++){
		input[i].index = i;
		scanf("%d",&input[i].CITY);
	}

	for(int i = 0; i < N; i++){

		scanf("%d",&input[i].OUTER);
	}

	sort(input,input+N);

	for(int i = 0; i < N; i++){
		MAP[input[i].index] = i;
		num_city[i] = input[i].CITY;
		num_outer[i] = input[i].OUTER;
	}

	int from_country,from_city,to_country,to_city,cost;

	for(int i = 0; i < K; i++){

		scanf("%d %d %d %d %d",&from_country,&from_city,&to_country,&to_city,&cost);
		from_country--;
		from_city--;
		to_country--;
		to_city--;

		from_country = MAP[from_country];
		to_country = MAP[to_country];

		if(from_country == to_country){

			same_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			same_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));

		}else{

			diff_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			diff_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));
		}

		DIST[from_country][from_city][to_country][to_city] = cost;
		DIST[to_country][to_city][from_country][from_city] = cost;
	}

	if(N == 1){

		calc_one();
		return 0;
	}

	calc_LAST_NEXT();
	int start = 0;

	if(num_outer[0] == 4 && num_city[0] > 4){
		calc_dp(0);
		start = 1;
		calc_zero(num_outer[0]);
	}

	for(int i = start; i < N; i++){

		if(num_outer[i] == 1){

			int IN[4] = {0,-1,-1,-1};
			int OUT[4] = {0,-1,-1,-1};
			int COST[3] = {0,-1,-1};
			int L[3];

			if(num_city[i] > 1){

				printf("-1\n");
				return 0;

			}else{

				info[i].push_back(Info(1,IN,OUT,COST,-1,0,L));
			}

		}else if(num_outer[i] == 2){

			calc_dp(i);
			calc_2(i);

		}else if(num_outer[i] == 3){

			calc_dp(i);

			int work_3[3];

			calc_2(i);

			for(int a = 0; a < 3; a++){

				work_3[a] = a;
			}
			calc_3(i,work_3);

		}else{ //num_outer[i] == 4

			calc_dp(i);

			calc_2(i);

			int work_3[3],work_4[4];

			for(int state = 1; state < POW[4]; state++){
				vector<int> vec;
				for(int loop = 0; loop < 4; loop++){
					if(state&POW[loop]){

						vec.push_back(loop);
					}
				}
				if(vec.size() == 1)continue;

				if(vec.size() == 2){

					continue;

				}else if(vec.size() == 3){

					work_3[0] = vec[0];
					work_3[1] = vec[1];
					work_3[2] = vec[2];

					calc_3(i,work_3);

				}else{

					for(int a = 0; a < 4; a++){

						work_4[a] = vec[a];
					}

					calc_4(i,work_4);
				}
			}
		}
	}

	for(int i = 0; i < N; i++){
		if(info[i].size() == 0){

			printf("-1\n");
			return 0;
		}
	}


	ans = BIG_NUM;
	recursive(0);

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}

	return 0;
}
accuracy: 1
time_ms: 4170
memory_kb: 169456
final_rank: 5

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 15
#define NUM 32768

struct Edge{
	Edge(int arg_to_country,int arg_to_city,int arg_cost){
		to_country = arg_to_country;
		to_city = arg_to_city;
		cost = arg_cost;
	}
	int to_country,to_city,cost;
};

struct INPUT{
	bool operator<(const struct INPUT &arg) const{

		if(OUTER != arg.OUTER){
			return OUTER > arg.OUTER;
		}else{
			return CITY > arg.CITY;
		}
	}
	int index,CITY,OUTER;
};

struct Edge2{
	Edge2(int arg_to,int arg_cost){
		to = arg_to;
		cost = arg_cost;
	}
	int to,cost;
};

struct Info{
	Info(int arg_num_out,int arg_IN[4],int arg_OUT[4],int arg_COST[3],int arg_COUNT,int arg_num_L,int arg_L[3]){
		num_out = arg_num_out;
		for(int i = 0; i < num_out; i++){
			IN[i] = arg_IN[i];
			OUT[i] = arg_OUT[i];
		}
		for(int i = 0; i < 3; i++){

			COST[i] = arg_COST[i];
			L[i] = arg_L[i];
		}
		num_L = arg_num_L;
		COUNT = arg_COUNT;
	}
	int num_out,IN[4],OUT[4],COST[3],num_L,L[3],COUNT;
};

struct Data{
	void set(int arg_country,int arg_left,int arg_right){
		country = arg_country;
		left = arg_left;
		right = arg_right;
	}
	int country;
	int left,right;
};

struct DEBUG{

	int pre_state,pre_node;
};

int N,K;
int num_city[SIZE],num_outer[SIZE];
int POW[SIZE+1];
int STATE[SIZE];
int ONE[NUM][SIZE];
int DIST[SIZE][SIZE][SIZE][SIZE];
int work_dp[SIZE][NUM][SIZE];
int DP[NUM][SIZE];
int ans;
int num_STATE[SIZE+1];
int table[SIZE+1][NUM];
int LAST[SIZE+1][NUM][SIZE+1],num_LAST[SIZE+1][NUM];
int NEXT[SIZE+1][NUM][SIZE+1][SIZE+1];
int num_NEXT[SIZE+1][NUM][SIZE+1];
int NOT[NUM][SIZE+1],num_NOT[NUM];
bool used[SIZE][4][4][4][4],pair_used[SIZE][4][4];
Data DATA[SIZE];
vector<Edge> same_G[SIZE][SIZE],diff_G[SIZE][SIZE];
vector<Info> info[SIZE];
map<int,int> MAP;
INPUT input[SIZE+1];


void calc_2(int index){

	if(num_city[index] == 2){ //立ち寄り2回

		int IN[4] = {0,1,-1,-1};
		int OUT[4] = {0,1,-1,-1};
		int COST[3] = {0,-1,-1};
		int L[3];

		info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));

	}else{ //?入りsecond出

		for(int second = 0; second < num_outer[index]; second++){
			int num_L = 0;
			int IN[3] = {-1,-1,-1};
			int OUT[3] = {second,-1,-1};
			int COST[3] = {-1,-1,-1};
			int L[3];

			for(int first = 0; first < num_outer[index]; first++){
				if(first == second)continue;
				if(work_dp[first][POW[num_city[index]]-1][second] == BIG_NUM)continue;

				COST[num_L] = work_dp[first][POW[num_city[index]]-1][second];
				L[num_L++] = first;
			}
			if(num_L == 0)continue;
			if(num_L == 1){
				IN[0] = L[0];
				info[index].push_back(Info(1,IN,OUT,COST,-1,0,L));
			}else{
				info[index].push_back(Info(1,IN,OUT,COST,2,num_L,L));
			}
		}
	}
}

void calc_3(int index,int work[3]){

	int L[3];

	if(num_city[index] == 3){ //立ち寄り3回

		int IN[4] = {work[0],work[1],work[2],-1};
		int OUT[4] = {work[0],work[1],work[2],-1};
		int COST[3] = {0,-1,-1};

		info[index].push_back(Info(3,IN,OUT,COST,-1,0,L));

	}else{ //first立ち寄り,second入りthird出

		do{
			int first = work[0];
			int second = work[1];
			int third = work[2];

			int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

			if(work_dp[second][to_state][third] < BIG_NUM){

				int IN[4] = {first,second,-1,-1};
				int OUT[4] = {first,third,-1,-1};
				int COST[3] = {work_dp[second][to_state][third],-1,-1};

				info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));
			}

		}while(next_permutation(work,work+3));
	}
}

void calc_4(int index,int work[4]){

	int L[3];

	if(num_city[index] == 4){ //立ち寄り4回

		int IN[4] = {work[0],work[1],work[2],work[3]};
		int OUT[4] = {work[0],work[1],work[2],work[3]};
		int COST[3] = {0,-1,-1};

		info[index].push_back(Info(4,IN,OUT,COST,-1,0,L));

	}else{

		do{

			int a = work[0];
			int b = work[1];
			int c = work[2];
			int d = work[3];

			//a入りb出-c入d出
			if(!used[index][c][d][a][b]){
				used[index][a][b][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[c]+POW[d]);
				int tmp_cost = BIG_NUM;

				for(int from_state = 1; from_state <= to_state; from_state++){
					if(((from_state & POW[c]) == POW[c]) ||
						((from_state & POW[d]) == POW[d]) ||
						((from_state & POW[a]) != POW[a]) ||
						((from_state & POW[b]) != POW[b]))continue;
					if(work_dp[a][from_state][b] == BIG_NUM)continue;

					int rest_state = POW[num_city[index]]-1-from_state;
					if(work_dp[c][rest_state][d] == BIG_NUM)continue;

					tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
				}

				if(tmp_cost < BIG_NUM){

					int IN[4] = {a,c,-1,-1};
					int OUT[4] = {b,d,-1,-1};
					int COST[3] = {tmp_cost,-1,-1};

					info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));
				}
			}

			//a,b立ち寄り,c入d出
			if(!pair_used[index][c][d]){
				pair_used[index][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[a]+POW[b]);

				if(work_dp[c][to_state][d] < BIG_NUM){

					int IN[4] = {a,b,c,-1};
					int OUT[4] = {a,b,d,-1};
					int COST[3] = {work_dp[c][to_state][d],-1,-1};

					info[index].push_back(Info(3,IN,OUT,COST,-1,0,L));
				}
			}

		}while(next_permutation(work,work+4));
	}
}

void calc_zero(int count_outer){

	int L[3];

	for(int left = 0; left <= 2; left++){
		int IN[4] = {left,-1,-1,-1};
		int OUT[4] = {-1,-1,-1,-1};

		int COST[3];
		for(int i = 0; i < 3; i++){

			COST[i] = -1;
		}
		for(int right = left+1; right <= 3; right++){

			COST[right-(left+1)] = work_dp[left][POW[num_city[0]]-1][right]; //left入りright出
		}

		info[0].push_back(Info(1,IN,OUT,COST,2,0,L));
	}

	int first,second,third;

	int work[4] = {0,1,2,3};

	do{
		first = work[0];
		second = work[1];
		third = work[2];
		if(second > third)continue;

		int to_state = (POW[num_city[0]]-1)-POW[first]; //firstを除いてTSP

		if(work_dp[second][to_state][third] < BIG_NUM){

			int IN[4] = {first,second,-1,-1};
			int OUT[4] = {first,third,-1,-1};
			int COST[3] = {work_dp[second][to_state][third],-1,-1};

			info[0].push_back(Info(2,IN,OUT,COST,-1,0,L));
		}

	}while(next_permutation(work,work+4));

	int a,b,c,d;
	for(int loop = 0; loop < 6; loop++){
		if(loop == 0){
			a = 0;
			b = 1;
			c = 2;
			d = 3;
		}else if(loop == 1){
			a = 0;
			b = 1;
			c = 3;
			d = 2;
		}else if(loop == 2){
			a = 0;
			b = 2;
			c = 1;
			d = 3;
		}else if(loop == 3){
			a = 0;
			b = 2;
			c = 3;
			d = 1;
		}else if(loop == 4){
			a = 0;
			b = 3;
			c = 1;
			d = 2;
		}else{ //loop == 5
			a = 0;
			b = 3;
			c = 2;
			d = 1;
		}

		//a入りb出-c入d出
		int to_state = (POW[num_city[0]]-1)-(POW[c]+POW[d]);
		int tmp_cost = BIG_NUM;

		for(int from_state = 1; from_state <= to_state; from_state++){
			if(((from_state & POW[c]) == POW[c]) ||
				((from_state & POW[d]) == POW[d]) ||
				((from_state & POW[a]) != POW[a]) ||
				((from_state & POW[b]) != POW[b]))continue;
			if(work_dp[a][from_state][b] == BIG_NUM)continue;

			int rest_state = POW[num_city[0]]-1-from_state;
			if(work_dp[c][rest_state][d] == BIG_NUM)continue;

			tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
		}

		if(tmp_cost < BIG_NUM){

			int IN[4] = {a,c,-1,-1};
			int OUT[4] = {b,d,-1,-1};
			int COST[3] = {tmp_cost,-1,-1};

			info[0].push_back(Info(2,IN,OUT,COST,-1,0,L));
		}
	}

	for(int loop = 0; loop < 6; loop++){
		if(loop == 0){
			a = 2;
			b = 3;
			c = 0;
			d = 1;
		}else if(loop == 1){
			a = 1;
			b = 3;
			c = 0;
			d = 2;
		}else if(loop == 2){
			a = 1;
			b = 2;
			c = 0;
			d = 3;
		}else if(loop == 3){
			a = 0;
			b = 3;
			c = 1;
			d = 2;
		}else if(loop == 4){
			a = 0;
			b = 2;
			c = 1;
			d = 3;
		}else{ //loop == 5
			a = 0;
			b = 1;
			c = 2;
			d = 3;
		}

		//a,b立ち寄り,c入d出
		int to_state = (POW[num_city[0]]-1)-(POW[a]+POW[b]);

		if(work_dp[c][to_state][d] < BIG_NUM){

			int IN[4] = {a,b,c,-1};
			int OUT[4] = {a,b,d,-1};
			int COST[3] = {work_dp[c][to_state][d],-1,-1};
			info[0].push_back(Info(3,IN,OUT,COST,-1,0,L));
		}
	}
}

void calc_one(){

	if(num_city[0] == 1){

		printf("0\n");
		return;
	}

	int index = 0;

	for(int state = 0; state < POW[num_city[index]]; state++){
		for(int last = 0; last < num_city[index]; last++){

			ONE[state][last] = BIG_NUM;
		}
	}

	//経路は輪になるので、スタートは0として良いはず
	ONE[POW[0]][0] = 0;

	for(int state = 1; state < POW[num_city[index]]-1; state++){
		for(int last = 0; last < num_city[index]; last++){
			if(ONE[state][last] == BIG_NUM)continue;

			for(int i = 0; i < same_G[index][last].size(); i++){

				int next_node = same_G[index][last][i].to_city;

				if(state & POW[next_node])continue;

				int next_state = state+POW[next_node];
				int next_cost = ONE[state][last]+same_G[index][last][i].cost;

				ONE[next_state][next_node] = min(ONE[next_state][next_node],next_cost);
			}
		}
	}

	int ans = BIG_NUM;
	for(int last = 0; last < num_city[index]; last++){
		if(ONE[POW[num_city[index]]-1][last] == BIG_NUM)continue;

		ans = min(ans,ONE[POW[num_city[index]]-1][last]+DIST[0][last][0][0]);
	}

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}
}
void recursive(int index){

	if(index < N){

		for(int i = 0; i < info[index].size(); i++){

			STATE[index] = i;
			recursive(index+1);
		}
		return;
	}

	//index == N
	int num_DATA = 0;
	int add = 0;

	int work_DIST[SIZE][SIZE];
	for(int i = 0; i < SIZE; i++){
		for(int k = 0; k < SIZE; k++){

			work_DIST[i][k] = BIG_NUM;
		}
	}

	for(int i = 0; i < N; i++){
		int num = STATE[i];
		if(info[i][num].COUNT == -1){
			add += info[i][num].COST[0];
		}
		for(int k = 0; k < info[i][num].num_out; k++){

			DATA[num_DATA++].set(i,info[i][num].IN[k],info[i][STATE[i]].OUT[k]);
		}
	}

	if(add >= ans)return;

	for(int i = 1; i < num_DATA; i++){
		for(int k = 1; k < num_DATA; k++){
			if((k == i)||(num_city[DATA[i].country] < num_outer[DATA[i].country] && DATA[i].country == DATA[k].country))continue;
			if(DATA[k].left == -1)continue;

			int from_country = DATA[i].country;
			int from_city = DATA[i].right;

			int to_country = DATA[k].country;
			int to_city = DATA[k].left;

			if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

			work_DIST[i][k] = DIST[from_country][from_city][to_country][to_city];
		}
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		int state = table[num_DATA][i];
		for(int k = 0; k < num_LAST[num_DATA][state]; k++){

			DP[state][LAST[num_DATA][state][k]] = BIG_NUM;
		}
	}
	for(int last = 1; last < num_DATA; last++){

		DP[POW[num_DATA]-1][last] = BIG_NUM;
	}

	for(int k = 1; k < num_DATA; k++){
		if(info[0][STATE[0]].COUNT == -1){ //国0がnum2でない

				int from_country = 0;
				int from_city = DATA[0].right;

				if(DATA[k].left != -1){

					int to_country = DATA[k].country;
					int to_city = DATA[k].left;

					if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

					DP[POW[0]|POW[k]][k] = DIST[from_country][from_city][to_country][to_city];
				}else{

					int to_country = DATA[k].country;
					for(int a = 0; a < info[to_country][STATE[to_country]].num_L; a++){

						int to_city = info[to_country][STATE[to_country]].L[a];

						if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

						DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],
								DIST[from_country][from_city][to_country][to_city]+info[to_country][STATE[to_country]].COST[a]);
					}
				}

		}else{ //国0がnum2

			int left = DATA[0].left;
			for(int right = left+1; right <= 3; right++){

				int from_country = 0;
				int from_city = right;

				if(DATA[k].left != -1){

					int to_country = DATA[k].country;
					int to_city = DATA[k].left;

					if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;
					int tmp_cost = info[0][STATE[0]].COST[right-(left+1)];
					if(tmp_cost == BIG_NUM)continue;

					DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],DIST[from_country][from_city][to_country][to_city]+tmp_cost);
				}else{

					int tmp_cost = info[0][STATE[0]].COST[right-(left+1)];
					if(tmp_cost == BIG_NUM)continue;

					int to_country = DATA[k].country;
					for(int a = 0; a < info[to_country][STATE[to_country]].num_L; a++){

						int to_city = info[to_country][STATE[to_country]].L[a];
						if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

						DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],
								DIST[from_country][from_city][to_country][to_city]+info[to_country][STATE[to_country]].COST[a]+tmp_cost);
					}
				}
			}
		}
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		int state = table[num_DATA][i];
		int max_k = num_LAST[num_DATA][state];
		for(int k = 0; k < max_k; k++){
			int last = LAST[num_DATA][state][k];
			if(DP[state][last]==BIG_NUM)continue;
			int max_a = num_NEXT[num_DATA][state][k];
			for(int a = 0; a < max_a; a++){
				int next = NEXT[num_DATA][state][k][a];
				if(DATA[next].left != -1){
					DP[state|(1<<next)][next] = min(DP[state|(1<<next)][next],DP[state][last]+work_DIST[last][next]);
				}else{

					int from_country = DATA[last].country;
					int from_city = DATA[last].right;

					int to_country = DATA[next].country;
					int max_b = info[to_country][STATE[to_country]].num_L;

					for(int b = 0; b < max_b; b++){
						int to_city = info[to_country][STATE[to_country]].L[b];
						if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

						DP[state|(1<<next)][next] = min(DP[state|(1<<next)][next],
								DP[state][last]+DIST[from_country][from_city][to_country][to_city]+info[to_country][STATE[to_country]].COST[b]);
					}
				}
			}
		}
	}

	int tmp_ans = BIG_NUM;

	for(int last = 1; last < num_DATA; last++){
		if(DP[POW[num_DATA]-1][last] == BIG_NUM)continue;

		int pre_country = DATA[last].country;
		int pre_city = DATA[last].right;

		int next_country = DATA[0].country;
		int next_city = DATA[0].left;

		if(DIST[pre_country][pre_city][next_country][next_city] == BIG_NUM)continue;

		if(tmp_ans > DP[POW[num_DATA]-1][last]+
				DIST[pre_country][pre_city][next_country][next_city]){
			tmp_ans = DP[POW[num_DATA]-1][last]+
					DIST[pre_country][pre_city][next_country][next_city];
		}
	}

	if(tmp_ans < BIG_NUM){

		ans = min(ans,tmp_ans+add);
	}
}

void calc_dp(int index){

	for(int start = 0; start < num_outer[index]; start++){
		for(int state = 0; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){

				work_dp[start][state][last] = BIG_NUM;
			}
		}
	}

	for(int i = 0; i < num_outer[index]; i++){
		work_dp[i][POW[i]][i] = 0;
		for(int state = 1; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){
				if(work_dp[i][state][last] == BIG_NUM)continue;

				for(int next = 0; next < num_city[index]; next++){
					if(state & POW[next])continue;
					if(DIST[index][last][index][next] == BIG_NUM)continue;

					int next_state = state+POW[next];
					int next_cost = work_dp[i][state][last]+DIST[index][last][index][next];

					work_dp[i][next_state][next] = min(work_dp[i][next_state][next],next_cost);
				}
			}
		}
	}
}

void calc_LAST_NEXT(){

	for(int i = 2; i <= 15; i++){
		int maximum = POW[i];
		num_STATE[i] = 0;
		for(int state = 3; state <= maximum-3; state += 2){ //DATA[0]を訪問済の状態のみ列挙

			table[i][num_STATE[i]++] = state;

			num_NOT[state] = 0;
			for(int k = 1; k < i; k++){
				if(state&POW[k])continue;
				NOT[state][num_NOT[state]++] = k;
			}

			num_LAST[i][state] = 0;

			for(int last = 1; last < i; last++){
				if((state&POW[last]) == 0)continue;

				LAST[i][state][num_LAST[i][state]] = last;
				num_NEXT[i][state][num_LAST[i][state]] = 0;

				for(int next = 1; next < i; next++){
					if(next == last)continue;
					if(state&POW[next])continue;

					NEXT[i][state][num_LAST[i][state]][num_NEXT[i][state][num_LAST[i][state]]++] = next;
				}
				num_LAST[i][state]++;
			}
		}
	}
}

int main(){

	//double first = time(NULL);

	POW[0] = 1;
	for(int i = 1; i <= SIZE; i++){

		POW[i] = POW[i-1]*2;
	}

	for(int a = 0; a < SIZE; a++){
		for(int b = 0; b < SIZE; b++){
			for(int c = 0; c < SIZE; c++){
				for(int d = 0; d < SIZE; d++){
					DIST[a][b][c][d] = BIG_NUM;
				}
			}
		}
	}

	for(int i = 0; i < SIZE; i++){
		for(int a = 0; a < 4; a++){
			for(int b = 0; b < 4; b++){
				pair_used[i][a][b] = false;
				for(int c = 0; c < 4; c++){
					for(int d = 0; d < 4; d++){
						used[i][a][b][c][d] = false;
					}
				}
			}
		}
	}

	scanf("%d %d",&N,&K);

	for(int i = 0; i < N; i++){
		input[i].index = i;
		scanf("%d",&input[i].CITY);
	}

	for(int i = 0; i < N; i++){

		scanf("%d",&input[i].OUTER);
	}

	sort(input,input+N);

	for(int i = 0; i < N; i++){
		MAP[input[i].index] = i;
		num_city[i] = input[i].CITY;
		num_outer[i] = input[i].OUTER;
	}

	int from_country,from_city,to_country,to_city,cost;

	for(int i = 0; i < K; i++){

		scanf("%d %d %d %d %d",&from_country,&from_city,&to_country,&to_city,&cost);
		from_country--;
		from_city--;
		to_country--;
		to_city--;

		from_country = MAP[from_country];
		to_country = MAP[to_country];

		if(from_country == to_country){

			same_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			same_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));

		}else{

			diff_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			diff_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));
		}

		DIST[from_country][from_city][to_country][to_city] = cost;
		DIST[to_country][to_city][from_country][from_city] = cost;
	}

	if(N == 1){

		calc_one();
		return 0;
	}

	calc_LAST_NEXT();
	int start = 0;

	if(num_outer[0] == 4 && num_city[0] > 4){
		calc_dp(0);
		start = 1;
		calc_zero(num_outer[0]);
	}

	for(int i = start; i < N; i++){

		if(num_outer[i] == 1){

			int IN[4] = {0,-1,-1,-1};
			int OUT[4] = {0,-1,-1,-1};
			int COST[3] = {0,-1,-1};
			int L[3];

			if(num_city[i] > 1){

				printf("-1\n");
				return 0;

			}else{

				info[i].push_back(Info(1,IN,OUT,COST,-1,0,L));
			}

		}else if(num_outer[i] == 2){

			calc_dp(i);

			int work[2] = {0,1};

			calc_2(i);

		}else if(num_outer[i] == 3){

			calc_dp(i);

			int work_3[3];

			calc_2(i);

			for(int a = 0; a < 3; a++){

				work_3[a] = a;
			}
			calc_3(i,work_3);

		}else{ //num_outer[i] == 4

			calc_dp(i);

			calc_2(i);

			int work_2[2],work_3[3],work_4[4];

			for(int state = 1; state < POW[4]; state++){
				vector<int> vec;
				for(int loop = 0; loop < 4; loop++){
					if(state&POW[loop]){

						vec.push_back(loop);
					}
				}
				if(vec.size() == 1)continue;

				if(vec.size() == 2){

					continue;

				}else if(vec.size() == 3){

					work_3[0] = vec[0];
					work_3[1] = vec[1];
					work_3[2] = vec[2];

					calc_3(i,work_3);

				}else{

					for(int a = 0; a < 4; a++){

						work_4[a] = vec[a];
					}

					calc_4(i,work_4);
				}
			}
		}
	}

	for(int i = 0; i < N; i++){
		if(info[i].size() == 0){

			printf("-1\n");
			return 0;
		}
	}

	ans = BIG_NUM;
	recursive(0);

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}

	//double last = time(NULL);

	//printf("%.3lf\n",(last-first));


	return 0;
}
accuracy: 0.35714285714285715
time_ms: 60
memory_kb: 81852
final_rank: 12

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 15
#define NUM 32768

struct Edge{
	Edge(int arg_to_country,int arg_to_city,int arg_cost){
		to_country = arg_to_country;
		to_city = arg_to_city;
		cost = arg_cost;
	}
	int to_country,to_city,cost;
};

struct INPUT{
	bool operator<(const struct INPUT &arg) const{

		if(OUTER != arg.OUTER){
			return OUTER > arg.OUTER;
		}else{
			return CITY > arg.CITY;
		}
	}
	int index,CITY,OUTER;
};

struct Edge2{
	Edge2(int arg_to,int arg_cost){
		to = arg_to;
		cost = arg_cost;
	}
	int to,cost;
};

struct Info{
	Info(int arg_num_out,int arg_IN[4],int arg_OUT[4],int arg_COST[3],int arg_COUNT,int arg_num_L,int arg_L[3]){
		num_out = arg_num_out;
		for(int i = 0; i < num_out; i++){
			IN[i] = arg_IN[i];
			OUT[i] = arg_OUT[i];
		}
		for(int i = 0; i < 3; i++){

			COST[i] = arg_COST[i];
			L[i] = arg_L[i];
		}
		num_L = arg_num_L;
		COUNT = arg_COUNT;
	}
	int num_out,IN[4],OUT[4],COST[3],num_L,L[3],COUNT;
};

struct Data{
	void set(int arg_country,int arg_left,int arg_right){
		country = arg_country;
		left = arg_left;
		right = arg_right;
	}
	int country;
	int left,right;
};

struct DEBUG{

	int pre_state,pre_node;
};

int N,K;
int num_city[SIZE],num_outer[SIZE];
int POW[SIZE+1];
int STATE[SIZE];
int ONE[NUM][SIZE];
int DIST[SIZE][SIZE][SIZE][SIZE];
int work_dp[SIZE][NUM][SIZE];
int DP[NUM][SIZE];
int ans;
int num_STATE[SIZE+1];
int table[SIZE+1][NUM];
int LAST[SIZE+1][NUM][SIZE+1],num_LAST[SIZE+1][NUM];
int NEXT[SIZE+1][NUM][SIZE+1][SIZE+1];
int num_NEXT[SIZE+1][NUM][SIZE+1];
int NOT[NUM][SIZE+1],num_NOT[NUM];
bool used[SIZE][4][4][4][4],pair_used[SIZE][4][4];
Data DATA[SIZE];
vector<Edge> same_G[SIZE][SIZE],diff_G[SIZE][SIZE];
vector<Info> info[SIZE];
map<int,int> MAP;
INPUT input[SIZE+1];


void calc_2(int index){

	if(num_city[index] == 2){ //立ち寄り2回

		int IN[4] = {0,1,-1,-1};
		int OUT[4] = {0,1,-1,-1};
		int COST[3] = {0,-1,-1};
		int L[3];

		info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));

	}else{ //?入りsecond出

		for(int second = 0; second < num_outer[index]; second++){
			int num_L = 0;
			int IN[3] = {-1,-1,-1};
			int OUT[3] = {second,-1,-1};
			int COST[3] = {-1,-1,-1};
			int L[3];

			for(int first = 0; first < num_outer[index]; first++){
				if(first == second)continue;
				if(work_dp[first][POW[num_city[index]]-1][second] == BIG_NUM)continue;

				COST[num_L] = work_dp[first][POW[num_city[index]]-1][second];
				L[num_L++] = first;
			}
			if(num_L == 0)continue;
			info[index].push_back(Info(1,IN,OUT,COST,2,num_L,L));
		}
	}
}

void calc_3(int index,int work[3]){

	int L[3];

	if(num_city[index] == 3){ //立ち寄り3回

		int IN[4] = {work[0],work[1],work[2],-1};
		int OUT[4] = {work[0],work[1],work[2],-1};
		int COST[3] = {0,-1,-1};

		info[index].push_back(Info(3,IN,OUT,COST,-1,0,L));

	}else{ //first立ち寄り,second入りthird出

		do{
			int first = work[0];
			int second = work[1];
			int third = work[2];

			int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

			if(work_dp[second][to_state][third] < BIG_NUM){

				int IN[4] = {first,second,-1,-1};
				int OUT[4] = {first,third,-1,-1};
				int COST[3] = {work_dp[second][to_state][third],-1,-1};

				info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));
			}

		}while(next_permutation(work,work+3));
	}
}

void calc_4(int index,int work[4]){

	int L[3];

	if(num_city[index] == 4){ //立ち寄り4回

		int IN[4] = {work[0],work[1],work[2],work[3]};
		int OUT[4] = {work[0],work[1],work[2],work[3]};
		int COST[3] = {0,-1,-1};

		info[index].push_back(Info(4,IN,OUT,COST,-1,0,L));

	}else{

		do{

			int a = work[0];
			int b = work[1];
			int c = work[2];
			int d = work[3];

			//a入りb出-c入d出
			if(!used[index][c][d][a][b]){
				used[index][a][b][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[c]+POW[d]);
				int tmp_cost = BIG_NUM;

				for(int from_state = 1; from_state <= to_state; from_state++){
					if(((from_state & POW[c]) == POW[c]) ||
						((from_state & POW[d]) == POW[d]) ||
						((from_state & POW[a]) != POW[a]) ||
						((from_state & POW[b]) != POW[b]))continue;
					if(work_dp[a][from_state][b] == BIG_NUM)continue;

					int rest_state = POW[num_city[index]]-1-from_state;
					if(work_dp[c][rest_state][d] == BIG_NUM)continue;

					tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
				}

				if(tmp_cost < BIG_NUM){

					int IN[4] = {a,c,-1,-1};
					int OUT[4] = {b,d,-1,-1};
					int COST[3] = {tmp_cost,-1,-1};

					info[index].push_back(Info(2,IN,OUT,COST,-1,0,L));
				}
			}

			//a,b立ち寄り,c入d出
			if(!pair_used[index][c][d]){
				pair_used[index][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[a]+POW[b]);

				if(work_dp[c][to_state][d] < BIG_NUM){

					int IN[4] = {a,b,c,-1};
					int OUT[4] = {a,b,d,-1};
					int COST[3] = {work_dp[c][to_state][d],-1,-1};

					info[index].push_back(Info(3,IN,OUT,COST,-1,0,L));
				}
			}

		}while(next_permutation(work,work+4));
	}
}

void calc_zero(int count_outer){

	int L[3];

	for(int left = 0; left <= 2; left++){
		int IN[4] = {left,-1,-1,-1};
		int OUT[4] = {-1,-1,-1,-1};

		int COST[3];
		for(int i = 0; i < 3; i++){

			COST[i] = -1;
		}
		for(int right = left+1; right <= 3; right++){

			COST[right-(left+1)] = work_dp[left][POW[num_city[0]]-1][right]; //left入りright出
		}

		info[0].push_back(Info(1,IN,OUT,COST,2,0,L));
	}

	int first,second,third;

	int work[4] = {0,1,2,3};

	do{
		first = work[0];
		second = work[1];
		third = work[2];
		if(second > third)continue;

		int to_state = (POW[num_city[0]]-1)-POW[first]; //firstを除いてTSP

		if(work_dp[second][to_state][third] < BIG_NUM){

			int IN[4] = {first,second,-1,-1};
			int OUT[4] = {first,third,-1,-1};
			int COST[3] = {work_dp[second][to_state][third],-1,-1};

			info[0].push_back(Info(2,IN,OUT,COST,-1,0,L));
		}

	}while(next_permutation(work,work+4));

	int a,b,c,d;
	for(int loop = 0; loop < 6; loop++){
		if(loop == 0){
			a = 0;
			b = 1;
			c = 2;
			d = 3;
		}else if(loop == 1){
			a = 0;
			b = 1;
			c = 3;
			d = 2;
		}else if(loop == 2){
			a = 0;
			b = 2;
			c = 1;
			d = 3;
		}else if(loop == 3){
			a = 0;
			b = 2;
			c = 3;
			d = 1;
		}else if(loop == 4){
			a = 0;
			b = 3;
			c = 1;
			d = 2;
		}else{ //loop == 5
			a = 0;
			b = 3;
			c = 2;
			d = 1;
		}

		//a入りb出-c入d出
		int to_state = (POW[num_city[0]]-1)-(POW[c]+POW[d]);
		int tmp_cost = BIG_NUM;

		for(int from_state = 1; from_state <= to_state; from_state++){
			if(((from_state & POW[c]) == POW[c]) ||
				((from_state & POW[d]) == POW[d]) ||
				((from_state & POW[a]) != POW[a]) ||
				((from_state & POW[b]) != POW[b]))continue;
			if(work_dp[a][from_state][b] == BIG_NUM)continue;

			int rest_state = POW[num_city[0]]-1-from_state;
			if(work_dp[c][rest_state][d] == BIG_NUM)continue;

			tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
		}

		if(tmp_cost < BIG_NUM){

			int IN[4] = {a,c,-1,-1};
			int OUT[4] = {b,d,-1,-1};
			int COST[3] = {tmp_cost,-1,-1};

			info[0].push_back(Info(2,IN,OUT,COST,-1,0,L));
		}
	}

	for(int loop = 0; loop < 6; loop++){
		if(loop == 0){
			a = 2;
			b = 3;
			c = 0;
			d = 1;
		}else if(loop == 1){
			a = 1;
			b = 3;
			c = 0;
			d = 2;
		}else if(loop == 2){
			a = 1;
			b = 2;
			c = 0;
			d = 3;
		}else if(loop == 3){
			a = 0;
			b = 3;
			c = 1;
			d = 2;
		}else if(loop == 4){
			a = 0;
			b = 2;
			c = 1;
			d = 3;
		}else{ //loop == 5
			a = 0;
			b = 1;
			c = 2;
			d = 3;
		}

		//a,b立ち寄り,c入d出
		int to_state = (POW[num_city[0]]-1)-(POW[a]+POW[b]);

		if(work_dp[c][to_state][d] < BIG_NUM){

			int IN[4] = {a,b,c,-1};
			int OUT[4] = {a,b,d,-1};
			int COST[3] = {work_dp[c][to_state][d],-1,-1};
			info[0].push_back(Info(3,IN,OUT,COST,-1,0,L));
		}
	}
}

void calc_one(){

	if(num_city[0] == 1){

		printf("0\n");
		return;
	}

	int index = 0;

	for(int state = 0; state < POW[num_city[index]]; state++){
		for(int last = 0; last < num_city[index]; last++){

			ONE[state][last] = BIG_NUM;
		}
	}

	//経路は輪になるので、スタートは0として良いはず
	ONE[POW[0]][0] = 0;

	for(int state = 1; state < POW[num_city[index]]-1; state++){
		for(int last = 0; last < num_city[index]; last++){
			if(ONE[state][last] == BIG_NUM)continue;

			for(int i = 0; i < same_G[index][last].size(); i++){

				int next_node = same_G[index][last][i].to_city;

				if(state & POW[next_node])continue;

				int next_state = state+POW[next_node];
				int next_cost = ONE[state][last]+same_G[index][last][i].cost;

				ONE[next_state][next_node] = min(ONE[next_state][next_node],next_cost);
			}
		}
	}

	int ans = BIG_NUM;
	for(int last = 0; last < num_city[index]; last++){
		if(ONE[POW[num_city[index]]-1][last] == BIG_NUM)continue;

		ans = min(ans,ONE[POW[num_city[index]]-1][last]+DIST[0][last][0][0]);
	}

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}
}
void recursive(int index){

	if(index < N){

		for(int i = 0; i < info[index].size(); i++){

			STATE[index] = i;
			recursive(index+1);
		}
		return;
	}

	//index == N
	int num_DATA = 0;
	int add = 0;

	int work_DIST[SIZE][SIZE];
	for(int i = 0; i < SIZE; i++){
		for(int k = 0; k < SIZE; k++){

			work_DIST[i][k] = BIG_NUM;
		}
	}

	for(int i = 0; i < N; i++){
		int num = STATE[i];
		if(info[i][num].COUNT == -1){
			add += info[i][num].COST[0];
		}
		for(int k = 0; k < info[i][num].num_out; k++){

			DATA[num_DATA++].set(i,info[i][num].IN[k],info[i][STATE[i]].OUT[k]);
		}
	}

	if(add >= ans)return;

	for(int i = 1; i < num_DATA; i++){
		for(int k = 1; k < num_DATA; k++){
			if((k == i)||(num_city[DATA[i].country] < num_outer[DATA[i].country] && DATA[i].country == DATA[k].country))continue;
			if(DATA[k].left == -1)continue;

			int from_country = DATA[i].country;
			int from_city = DATA[i].right;

			int to_country = DATA[k].country;
			int to_city = DATA[k].left;

			if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

			work_DIST[i][k] = DIST[from_country][from_city][to_country][to_city];
		}
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		int state = table[num_DATA][i];
		for(int k = 0; k < num_LAST[num_DATA][state]; k++){

			DP[state][LAST[num_DATA][state][k]] = BIG_NUM;
		}
	}
	for(int last = 1; last < num_DATA; last++){

		DP[POW[num_DATA]-1][last] = BIG_NUM;
	}

	for(int k = 1; k < num_DATA; k++){
		if(info[0][STATE[0]].COUNT == -1){ //国0がnum2でない

				int from_country = 0;
				int from_city = DATA[0].right;

				if(DATA[k].left != -1){

					int to_country = DATA[k].country;
					int to_city = DATA[k].left;

					if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

					DP[POW[0]|POW[k]][k] = DIST[from_country][from_city][to_country][to_city];
				}else{

					int to_country = DATA[k].country;
					for(int a = 0; a < info[to_country][STATE[to_country]].num_L; a++){

						int to_city = info[to_country][STATE[to_country]].L[a];

						if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

						DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],
								DIST[from_country][from_city][to_country][to_city]+info[to_country][STATE[to_country]].COST[a]);
					}
				}

		}else{ //国0がnum2

			int left = DATA[0].left;
			for(int right = left+1; right <= 3; right++){

				int from_country = 0;
				int from_city = right;

				if(DATA[k].left != -1){

					int to_country = DATA[k].country;
					int to_city = DATA[k].left;

					if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;
					int tmp_cost = info[0][STATE[0]].COST[right-(left+1)];
					if(tmp_cost == BIG_NUM)continue;

					DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],DIST[from_country][from_city][to_country][to_city]+tmp_cost);
				}else{

					int tmp_cost = info[0][STATE[0]].COST[right-(left+1)];
					if(tmp_cost == BIG_NUM)continue;

					int to_country = DATA[k].country;
					for(int a = 0; a < info[to_country][STATE[to_country]].num_L; a++){

						int to_city = info[to_country][STATE[to_country]].L[a];
						if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

						DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],
								DIST[from_country][from_city][to_country][to_city]+info[to_country][STATE[to_country]].COST[a]+tmp_cost);
					}
				}
			}
		}
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		int state = table[num_DATA][i];
		int max_k = num_LAST[num_DATA][state];
		for(int k = 0; k < max_k; k++){
			int last = LAST[num_DATA][state][k];
			if(DP[state][last]==BIG_NUM)continue;
			int max_a = num_NEXT[num_DATA][state][k];
			for(int a = 0; a < max_a; a++){
				int next = NEXT[num_DATA][state][k][a];
				if(DATA[next].left != -1){
					DP[state|(1<<next)][next] = min(DP[state|(1<<next)][next],DP[state][last]+work_DIST[last][next]);
				}else{

					int from_country = DATA[last].country;
					int from_city = DATA[last].right;

					int to_country = DATA[next].country;

					for(int b = 0; b < info[to_country][STATE[to_country]].num_L; b++){
						int to_city = info[to_country][STATE[to_country]].L[b];
						if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

						DP[state|(1<<next)][next] = min(DP[state|(1<<next)][next],
								DP[state][last]+DIST[from_country][from_city][to_country][to_city]+info[to_country][STATE[to_country]].COST[b]);
					}
				}
			}
		}
	}

	int tmp_ans = BIG_NUM;

	for(int last = 1; last < num_DATA; last++){
		if(DP[POW[num_DATA]-1][last] == BIG_NUM)continue;

		int pre_country = DATA[last].country;
		int pre_city = DATA[last].right;

		int next_country = DATA[0].country;
		int next_city = DATA[0].left;

		if(DIST[pre_country][pre_city][next_country][next_city] == BIG_NUM)continue;

		if(tmp_ans > DP[POW[num_DATA]-1][last]+
				DIST[pre_country][pre_city][next_country][next_city]){
			tmp_ans = DP[POW[num_DATA]-1][last]+
					DIST[pre_country][pre_city][next_country][next_city];
		}
	}

	if(tmp_ans < BIG_NUM){

		ans = min(ans,tmp_ans+add);
	}
}

void calc_dp(int index){

	for(int start = 0; start < num_outer[index]; start++){
		for(int state = 0; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){

				work_dp[start][state][last] = BIG_NUM;
			}
		}
	}

	for(int i = 0; i < num_outer[index]; i++){
		work_dp[i][POW[i]][i] = 0;
		for(int state = 1; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){
				if(work_dp[i][state][last] == BIG_NUM)continue;

				for(int next = 0; next < num_city[index]; next++){
					if(state & POW[next])continue;
					if(DIST[index][last][index][next] == BIG_NUM)continue;

					int next_state = state+POW[next];
					int next_cost = work_dp[i][state][last]+DIST[index][last][index][next];

					work_dp[i][next_state][next] = min(work_dp[i][next_state][next],next_cost);
				}
			}
		}
	}
}

void calc_LAST_NEXT(){

	for(int i = 2; i <= 15; i++){
		int maximum = POW[i];
		num_STATE[i] = 0;
		for(int state = 3; state <= maximum-3; state += 2){ //DATA[0]を訪問済の状態のみ列挙

			table[i][num_STATE[i]++] = state;

			num_NOT[state] = 0;
			for(int k = 1; k < i; k++){
				if(state&POW[k])continue;
				NOT[state][num_NOT[state]++] = k;
			}

			num_LAST[i][state] = 0;

			for(int last = 1; last < i; last++){
				if((state&POW[last]) == 0)continue;

				LAST[i][state][num_LAST[i][state]] = last;
				num_NEXT[i][state][num_LAST[i][state]] = 0;

				for(int next = 1; next < i; next++){
					if(next == last)continue;
					if(state&POW[next])continue;

					NEXT[i][state][num_LAST[i][state]][num_NEXT[i][state][num_LAST[i][state]]++] = next;
				}
				num_LAST[i][state]++;
			}
		}
	}
}

int main(){

	POW[0] = 1;
	for(int i = 1; i <= SIZE; i++){

		POW[i] = POW[i-1]*2;
	}

	for(int a = 0; a < SIZE; a++){
		for(int b = 0; b < SIZE; b++){
			for(int c = 0; c < SIZE; c++){
				for(int d = 0; d < SIZE; d++){
					DIST[a][b][c][d] = BIG_NUM;
				}
			}
		}
	}

	for(int i = 0; i < SIZE; i++){
		for(int a = 0; a < 4; a++){
			for(int b = 0; b < 4; b++){
				pair_used[i][a][b] = false;
				for(int c = 0; c < 4; c++){
					for(int d = 0; d < 4; d++){
						used[i][a][b][c][d] = false;
					}
				}
			}
		}
	}

	scanf("%d %d",&N,&K);

	for(int i = 0; i < N; i++){
		input[i].index = i;
		scanf("%d",&input[i].CITY);
	}

	for(int i = 0; i < N; i++){

		scanf("%d",&input[i].OUTER);
	}

	sort(input,input+N);

	for(int i = 0; i < N; i++){
		MAP[input[i].index] = i;
		num_city[i] = input[i].CITY;
		num_outer[i] = input[i].OUTER;
	}

	int from_country,from_city,to_country,to_city,cost;

	for(int i = 0; i < K; i++){

		scanf("%d %d %d %d %d",&from_country,&from_city,&to_country,&to_city,&cost);
		from_country--;
		from_city--;
		to_country--;
		to_city--;

		from_country = MAP[from_country];
		to_country = MAP[to_country];

		if(from_country == to_country){

			same_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			same_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));

		}else{

			diff_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			diff_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));
		}

		DIST[from_country][from_city][to_country][to_city] = cost;
		DIST[to_country][to_city][from_country][from_city] = cost;
	}

	if(N == 1){

		calc_one();
		return 0;
	}

	calc_LAST_NEXT();
	int start = 0;

	if(num_outer[0] == 4 && num_city[0] > 4){
		calc_dp(0);
		start = 1;
		calc_zero(num_outer[0]);
	}

	for(int i = start; i < N; i++){

		if(num_outer[i] == 1){

			int IN[4] = {0,-1,-1,-1};
			int OUT[4] = {0,-1,-1,-1};
			int COST[3] = {0,-1,-1};
			int L[3];

			if(num_city[i] > 1){

				printf("-1\n");
				return 0;

			}else{

				info[i].push_back(Info(1,IN,OUT,COST,-1,0,L));
			}

		}else if(num_outer[i] == 2){

			calc_dp(i);

			int work[2] = {0,1};

			calc_2(i);

		}else if(num_outer[i] == 3){

			calc_dp(i);

			int work_3[3];

			calc_2(i);

			for(int a = 0; a < 3; a++){

				work_3[a] = a;
			}
			calc_3(i,work_3);

		}else{ //num_outer[i] == 4

			calc_dp(i);

			calc_2(i);

			int work_2[2],work_3[3],work_4[4];

			for(int state = 1; state < POW[4]; state++){
				vector<int> vec;
				for(int loop = 0; loop < 4; loop++){
					if(state&POW[loop]){

						vec.push_back(loop);
					}
				}
				if(vec.size() == 1)continue;

				if(vec.size() == 2){

					continue;

				}else if(vec.size() == 3){

					work_3[0] = vec[0];
					work_3[1] = vec[1];
					work_3[2] = vec[2];

					calc_3(i,work_3);

				}else{

					for(int a = 0; a < 4; a++){

						work_4[a] = vec[a];
					}

					calc_4(i,work_4);
				}
			}
		}
	}

	for(int i = 0; i < N; i++){
		if(info[i].size() == 0){

			printf("-1\n");
			return 0;
		}
	}

	ans = BIG_NUM;
	recursive(0);

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}

	return 0;
}
accuracy: 0.014285714285714285
time_ms: 20
memory_kb: 79920
final_rank: 17

code_snippet: #include<bits/stdc++.h>
/*m(_ _)m申し訳ございません...*/
#pragma GCC target("avx")
#pragma GCC optimize("O3")
/*m(_ _)m申し訳ございません...*/
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 15
#define NUM 32768

struct Edge{
	Edge(int arg_to_country,int arg_to_city,int arg_cost){
		to_country = arg_to_country;
		to_city = arg_to_city;
		cost = arg_cost;
	}
	int to_country,to_city,cost;
};

struct INPUT{
	bool operator<(const struct INPUT &arg) const{

		if(OUTER != arg.OUTER){
			return OUTER > arg.OUTER;
		}else{
			return CITY > arg.CITY;
		}
	}
	int index,CITY,OUTER;
};

struct Edge2{
	Edge2(int arg_to,int arg_cost){
		to = arg_to;
		cost = arg_cost;
	}
	int to,cost;
};

struct Info{
	Info(int arg_num_out,int arg_IN[4],int arg_OUT[4],int arg_COST[3],int arg_COUNT){
		num_out = arg_num_out;
		for(int i = 0; i < num_out; i++){
			IN[i] = arg_IN[i];
			OUT[i] = arg_OUT[i];
		}
		for(int i = 0; i < 3; i++){

			COST[i] = arg_COST[i];
		}
		COUNT = arg_COUNT;
	}
	int num_out,IN[4],OUT[4],COST[3],COUNT;
};

struct Data{
	void set(int arg_country,int arg_left,int arg_right){
		country = arg_country;
		left = arg_left;
		right = arg_right;
	}
	int country;
	int left,right;
};

struct DEBUG{

	int pre_state,pre_node;
};

int N,K;
int num_city[SIZE],num_outer[SIZE];
int POW[SIZE+1];
int STATE[SIZE];
int ONE[NUM][SIZE];
int DIST[SIZE][SIZE][SIZE][SIZE];
int work_dp[SIZE][NUM][SIZE];
int DP[NUM][SIZE];
int ans;
int num_STATE[SIZE+1];
int table[SIZE+1][NUM];
int LAST[SIZE+1][NUM][SIZE+1],num_LAST[SIZE+1][NUM];
int NEXT[SIZE+1][NUM][SIZE+1][SIZE+1];
int num_NEXT[SIZE+1][NUM][SIZE+1];
int NOT[NUM][SIZE+1],num_NOT[NUM];
bool used[SIZE][4][4][4][4],pair_used[SIZE][4][4];
Data DATA[SIZE];
vector<Edge> same_G[SIZE][SIZE],diff_G[SIZE][SIZE];
vector<Info> info[SIZE];
map<int,int> MAP;
INPUT input[SIZE+1];


void calc_2(int index,int work[2]){

	if(num_city[index] == 2){ //立ち寄り2回

		int IN[4] = {work[0],work[1],-1,-1};
		int OUT[4] = {work[0],work[1],-1,-1};
		int COST[3] = {0,-1,-1};

		info[index].push_back(Info(2,IN,OUT,COST,-1));

	}else{ //first入りsecond出

		do{

			int first = work[0];
			int second = work[1];

			if(work_dp[first][POW[num_city[index]]-1][second] == BIG_NUM)continue;

			int tmp_cost = work_dp[first][POW[num_city[index]]-1][second];

			int IN[4] = {first,-1,-1,-1};
			int OUT[4] = {second,-1,-1,-1};
			int COST[3] = {tmp_cost,-1,-1};

			info[index].push_back(Info(1,IN,OUT,COST,-1));

		}while(next_permutation(work,work+2));
	}
}

void calc_3(int index,int work[3]){

	if(num_city[index] == 3){ //立ち寄り3回

		int IN[4] = {work[0],work[1],work[2],-1};
		int OUT[4] = {work[0],work[1],work[2],-1};
		int COST[3] = {0,-1,-1};

		info[index].push_back(Info(3,IN,OUT,COST,-1));

	}else{ //first立ち寄り,second入りthird出

		do{
			int first = work[0];
			int second = work[1];
			int third = work[2];

			int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

			if(work_dp[second][to_state][third] < BIG_NUM){

				int IN[4] = {first,second,-1,-1};
				int OUT[4] = {first,third,-1,-1};
				int COST[3] = {work_dp[second][to_state][third],-1,-1};

				info[index].push_back(Info(2,IN,OUT,COST,-1));
			}

		}while(next_permutation(work,work+3));
	}
}

void calc_4(int index,int work[4]){

	if(num_city[index] == 4){ //立ち寄り4回

		int IN[4] = {work[0],work[1],work[2],work[3]};
		int OUT[4] = {work[0],work[1],work[2],work[3]};
		int COST[3] = {0,-1,-1};

		info[index].push_back(Info(4,IN,OUT,COST,-1));

	}else{

		do{

			int a = work[0];
			int b = work[1];
			int c = work[2];
			int d = work[3];

			//a入りb出-c入d出
			if(!used[index][c][d][a][b]){
				used[index][a][b][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[c]+POW[d]);
				int tmp_cost = BIG_NUM;

				for(int from_state = 1; from_state <= to_state; from_state++){
					if(((from_state & POW[c]) == POW[c]) ||
						((from_state & POW[d]) == POW[d]) ||
						((from_state & POW[a]) != POW[a]) ||
						((from_state & POW[b]) != POW[b]))continue;
					if(work_dp[a][from_state][b] == BIG_NUM)continue;

					int rest_state = POW[num_city[index]]-1-from_state;
					if(work_dp[c][rest_state][d] == BIG_NUM)continue;

					tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
				}

				if(tmp_cost < BIG_NUM){

					int IN[4] = {a,c,-1,-1};
					int OUT[4] = {b,d,-1,-1};
					int COST[3] = {tmp_cost,-1,-1};

					info[index].push_back(Info(2,IN,OUT,COST,-1));
				}
			}

			//a,b立ち寄り,c入d出
			if(!pair_used[index][c][d]){
				pair_used[index][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[a]+POW[b]);

				if(work_dp[c][to_state][d] < BIG_NUM){

					int IN[4] = {a,b,c,-1};
					int OUT[4] = {a,b,d,-1};
					int COST[3] = {work_dp[c][to_state][d],-1,-1};

					info[index].push_back(Info(3,IN,OUT,COST,-1));
				}
			}

		}while(next_permutation(work,work+4));
	}
}

void calc_zero(int count_outer){

	for(int left = 0; left <= 2; left++){
		int IN[4] = {left,-1,-1,-1};
		int OUT[4] = {-1,-1,-1,-1};

		int COST[3];
		for(int i = 0; i < 3; i++){

			COST[i] = -1;
		}
		for(int right = left+1; right <= 3; right++){

			COST[right-(left+1)] = work_dp[left][POW[num_city[0]]-1][right]; //left入りright出
		}

		info[0].push_back(Info(1,IN,OUT,COST,2));
	}

	int first,second,third;

	int work[4] = {0,1,2,3};

	do{
		first = work[0];
		second = work[1];
		third = work[2];
		if(second > third)continue;

		int to_state = (POW[num_city[0]]-1)-POW[first]; //firstを除いてTSP

		if(work_dp[second][to_state][third] < BIG_NUM){

			int IN[4] = {first,second,-1,-1};
			int OUT[4] = {first,third,-1,-1};
			int COST[3] = {work_dp[second][to_state][third],-1,-1};

			info[0].push_back(Info(2,IN,OUT,COST,-1));
		}

	}while(next_permutation(work,work+4));

	int a,b,c,d;
	for(int loop = 0; loop < 6; loop++){
		if(loop == 0){
			a = 0;
			b = 1;
			c = 2;
			d = 3;
		}else if(loop == 1){
			a = 0;
			b = 1;
			c = 3;
			d = 2;
		}else if(loop == 2){
			a = 0;
			b = 2;
			c = 1;
			d = 3;
		}else if(loop == 3){
			a = 0;
			b = 2;
			c = 3;
			d = 1;
		}else if(loop == 4){
			a = 0;
			b = 3;
			c = 1;
			d = 2;
		}else{ //loop == 5
			a = 0;
			b = 3;
			c = 2;
			d = 1;
		}

		//a入りb出-c入d出
		int to_state = (POW[num_city[0]]-1)-(POW[c]+POW[d]);
		int tmp_cost = BIG_NUM;

		for(int from_state = 1; from_state <= to_state; from_state++){
			if(((from_state & POW[c]) == POW[c]) ||
				((from_state & POW[d]) == POW[d]) ||
				((from_state & POW[a]) != POW[a]) ||
				((from_state & POW[b]) != POW[b]))continue;
			if(work_dp[a][from_state][b] == BIG_NUM)continue;

			int rest_state = POW[num_city[0]]-1-from_state;
			if(work_dp[c][rest_state][d] == BIG_NUM)continue;

			tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
		}

		if(tmp_cost < BIG_NUM){

			int IN[4] = {a,c,-1,-1};
			int OUT[4] = {b,d,-1,-1};
			int COST[3] = {tmp_cost,-1,-1};

			info[0].push_back(Info(2,IN,OUT,COST,-1));
		}
	}

	for(int loop = 0; loop < 6; loop++){
		if(loop == 0){
			a = 2;
			b = 3;
			c = 0;
			d = 1;
		}else if(loop == 1){
			a = 1;
			b = 3;
			c = 0;
			d = 2;
		}else if(loop == 2){
			a = 1;
			b = 2;
			c = 0;
			d = 3;
		}else if(loop == 3){
			a = 0;
			b = 3;
			c = 1;
			d = 2;
		}else if(loop == 4){
			a = 0;
			b = 2;
			c = 1;
			d = 3;
		}else{ //loop == 5
			a = 0;
			b = 1;
			c = 2;
			d = 3;
		}

		//a,b立ち寄り,c入d出
		int to_state = (POW[num_city[0]]-1)-(POW[a]+POW[b]);

		if(work_dp[c][to_state][d] < BIG_NUM){

			int IN[4] = {a,b,c,-1};
			int OUT[4] = {a,b,d,-1};
			int COST[3] = {work_dp[c][to_state][d],-1,-1};
			info[0].push_back(Info(3,IN,OUT,COST,-1));
		}
	}
}

void calc_one(){

	if(num_city[0] == 1){

		printf("0\n");
		return;
	}

	int index = 0;

	for(int state = 0; state < POW[num_city[index]]; state++){
		for(int last = 0; last < num_city[index]; last++){

			ONE[state][last] = BIG_NUM;
		}
	}

	//経路は輪になるので、スタートは0として良いはず
	ONE[POW[0]][0] = 0;

	for(int state = 1; state < POW[num_city[index]]-1; state++){
		for(int last = 0; last < num_city[index]; last++){
			if(ONE[state][last] == BIG_NUM)continue;

			for(int i = 0; i < same_G[index][last].size(); i++){

				int next_node = same_G[index][last][i].to_city;

				if(state & POW[next_node])continue;

				int next_state = state+POW[next_node];
				int next_cost = ONE[state][last]+same_G[index][last][i].cost;

				ONE[next_state][next_node] = min(ONE[next_state][next_node],next_cost);
			}
		}
	}

	int ans = BIG_NUM;
	for(int last = 0; last < num_city[index]; last++){
		if(ONE[POW[num_city[index]]-1][last] == BIG_NUM)continue;

		ans = min(ans,ONE[POW[num_city[index]]-1][last]+DIST[0][last][0][0]);
	}

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}
}
void recursive(int index){

	if(index < N){

		for(int i = 0; i < info[index].size(); i++){

			STATE[index] = i;
			recursive(index+1);
		}
		return;
	}

	//index == N
	int num_DATA = 0;
	int add = 0;

	int work_DIST[SIZE][SIZE];
	for(int i = 0; i < SIZE; i++){
		for(int k = 0; k < SIZE; k++){

			work_DIST[i][k] = BIG_NUM;
		}
	}

	for(int i = 0; i < N; i++){
		int num = STATE[i];
		if(i > 0 || info[i][num].COUNT == -1){
			add += info[i][num].COST[0];
		}
		for(int k = 0; k < info[i][num].num_out; k++){

			DATA[num_DATA++].set(i,info[i][num].IN[k],info[i][STATE[i]].OUT[k]);
		}
	}

	if(add >= ans)return;

	for(int i = 1; i < num_DATA; i++){
		for(int k = 1; k < num_DATA; k++){
			if((k == i)||(num_city[DATA[i].country] < num_outer[DATA[i].country] && DATA[i].country == DATA[k].country))continue;

			int from_country = DATA[i].country;
			int from_city = DATA[i].right;

			int to_country = DATA[k].country;
			int to_city = DATA[k].left;

			if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

			work_DIST[i][k] = DIST[from_country][from_city][to_country][to_city];
		}
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		int state = table[num_DATA][i];
		for(int k = 0; k < num_LAST[num_DATA][state]; k++){

			DP[state][LAST[num_DATA][state][k]] = BIG_NUM;
		}
	}
	for(int last = 1; last < num_DATA; last++){

		DP[POW[num_DATA]-1][last] = BIG_NUM;
	}

	for(int k = 1; k < num_DATA; k++){
		if(info[0][STATE[0]].COUNT == -1){

				int from_country = 0;
				int from_city = DATA[0].right;

				int to_country = DATA[k].country;
				int to_city = DATA[k].left;

				if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

				DP[POW[0]|POW[k]][k] = DIST[from_country][from_city][to_country][to_city];

		}else{ //国0がnum2

			int left = DATA[0].left;
			for(int right = left+1; right <= 3; right++){

				int from_country = 0;
				int from_city = right;

				int to_country = DATA[k].country;
				int to_city = DATA[k].left;

				if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;
				int tmp_cost = info[0][STATE[0]].COST[right-(left+1)];
				if(tmp_cost == BIG_NUM)continue;

				DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],DIST[from_country][from_city][to_country][to_city]+tmp_cost);
			}
		}
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		int state = table[num_DATA][i];
		int max_k = num_LAST[num_DATA][state];
		for(int k = 0; k < max_k; k++){
			int last = LAST[num_DATA][state][k];
			if(DP[state][last]==BIG_NUM)continue;
			int max_a = num_NEXT[num_DATA][state][k];
			for(int a = 0; a < max_a; a++){
				int next = NEXT[num_DATA][state][k][a];
				DP[state|(1<<next)][next] = min(DP[state|(1<<next)][next],
						DP[state][last]+work_DIST[last][next]);
			}
		}
	}

	int tmp_ans = BIG_NUM;

	for(int last = 1; last < num_DATA; last++){
		if(DP[POW[num_DATA]-1][last] == BIG_NUM)continue;

		int pre_country = DATA[last].country;
		int pre_city = DATA[last].right;

		int next_country = DATA[0].country;
		int next_city = DATA[0].left;

		if(DIST[pre_country][pre_city][next_country][next_city] == BIG_NUM)continue;

		if(tmp_ans > DP[POW[num_DATA]-1][last]+
				DIST[pre_country][pre_city][next_country][next_city]){
			tmp_ans = DP[POW[num_DATA]-1][last]+
					DIST[pre_country][pre_city][next_country][next_city];
		}
	}

	if(tmp_ans < BIG_NUM){

		ans = min(ans,tmp_ans+add);
	}
}

void calc_dp(int index){

	for(int start = 0; start < num_outer[index]; start++){
		for(int state = 0; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){

				work_dp[start][state][last] = BIG_NUM;
			}
		}
	}

	for(int i = 0; i < num_outer[index]; i++){
		work_dp[i][POW[i]][i] = 0;
		for(int state = 1; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){
				if(work_dp[i][state][last] == BIG_NUM)continue;

				for(int next = 0; next < num_city[index]; next++){
					if(state & POW[next])continue;
					if(DIST[index][last][index][next] == BIG_NUM)continue;

					int next_state = state+POW[next];
					int next_cost = work_dp[i][state][last]+DIST[index][last][index][next];

					work_dp[i][next_state][next] = min(work_dp[i][next_state][next],next_cost);
				}
			}
		}
	}
}

void calc_LAST_NEXT(){

	for(int i = 2; i <= 15; i++){
		int maximum = POW[i];
		num_STATE[i] = 0;
		for(int state = 3; state <= maximum-3; state += 2){ //DATA[0]を訪問済の状態のみ列挙

			table[i][num_STATE[i]++] = state;

			num_NOT[state] = 0;
			for(int k = 1; k < i; k++){
				if(state&POW[k])continue;
				NOT[state][num_NOT[state]++] = k;
			}

			num_LAST[i][state] = 0;

			for(int last = 1; last < i; last++){
				if((state&POW[last]) == 0)continue;

				LAST[i][state][num_LAST[i][state]] = last;
				num_NEXT[i][state][num_LAST[i][state]] = 0;

				for(int next = 1; next < i; next++){
					if(next == last)continue;
					if(state&POW[next])continue;

					NEXT[i][state][num_LAST[i][state]][num_NEXT[i][state][num_LAST[i][state]]++] = next;
				}
				num_LAST[i][state]++;
			}
		}
	}
}

int main(){

	POW[0] = 1;
	for(int i = 1; i <= SIZE; i++){

		POW[i] = POW[i-1]*2;
	}

	for(int a = 0; a < SIZE; a++){
		for(int b = 0; b < SIZE; b++){
			for(int c = 0; c < SIZE; c++){
				for(int d = 0; d < SIZE; d++){
					DIST[a][b][c][d] = BIG_NUM;
				}
			}
		}
	}

	for(int i = 0; i < SIZE; i++){
		for(int a = 0; a < 4; a++){
			for(int b = 0; b < 4; b++){
				pair_used[i][a][b] = false;
				for(int c = 0; c < 4; c++){
					for(int d = 0; d < 4; d++){
						used[i][a][b][c][d] = false;
					}
				}
			}
		}
	}

	scanf("%d %d",&N,&K);

	for(int i = 0; i < N; i++){
		input[i].index = i;
		scanf("%d",&input[i].CITY);
	}

	for(int i = 0; i < N; i++){

		scanf("%d",&input[i].OUTER);
	}

	sort(input,input+N);

	for(int i = 0; i < N; i++){
		MAP[input[i].index] = i;
		num_city[i] = input[i].CITY;
		num_outer[i] = input[i].OUTER;
	}

	int from_country,from_city,to_country,to_city,cost;

	for(int i = 0; i < K; i++){

		scanf("%d %d %d %d %d",&from_country,&from_city,&to_country,&to_city,&cost);
		from_country--;
		from_city--;
		to_country--;
		to_city--;

		from_country = MAP[from_country];
		to_country = MAP[to_country];

		if(from_country == to_country){

			same_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			same_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));

		}else{

			diff_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			diff_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));
		}

		DIST[from_country][from_city][to_country][to_city] = cost;
		DIST[to_country][to_city][from_country][from_city] = cost;
	}

	if(N == 1){

		calc_one();
		return 0;
	}

	calc_LAST_NEXT();
	int start = 0;

	if(num_outer[0] == 4 && num_city[0] > 4){
		calc_dp(0);
		start = 1;
		calc_zero(num_outer[0]);
	}

	for(int i = start; i < N; i++){

		if(num_outer[i] == 1){

			int IN[4] = {0,-1,-1,-1};
			int OUT[4] = {0,-1,-1,-1};
			int COST[3] = {0,-1,-1};

			if(num_city[i] > 1){

				printf("-1\n");
				return 0;

			}else{

				info[i].push_back(Info(1,IN,OUT,COST,-1));
			}

		}else if(num_outer[i] == 2){

			calc_dp(i);

			int work[2] = {0,1};

			calc_2(i,work);

		}else if(num_outer[i] == 3){

			calc_dp(i);

			int work_2[2],work_3[3];

			for(int state = 1; state < POW[3]; state++){
				vector<int> vec;
				for(int loop = 0; loop < 3; loop++){
					if(state&POW[loop]){

						vec.push_back(loop);
					}
				}
				if(vec.size() == 1)continue;

				if(vec.size() == 2){ //国際空港を2つ使う場合

					work_2[0] = vec[0];
					work_2[1] = vec[1];

					calc_2(i,work_2);

				}else{ //国際空港を3つ使う場合

					work_3[0] = vec[0];
					work_3[1] = vec[1];
					work_3[2] = vec[2];

					calc_3(i,work_3);
				}
			}

		}else{ //num_outer[i] == 4

			calc_dp(i);

			int work_2[2],work_3[3],work_4[4];

			for(int state = 1; state < POW[4]; state++){
				vector<int> vec;
				for(int loop = 0; loop < 4; loop++){
					if(state&POW[loop]){

						vec.push_back(loop);
					}
				}
				if(vec.size() == 1)continue;

				if(vec.size() == 2){

					work_2[0] = vec[0];
					work_2[1] = vec[1];

					calc_2(i,work_2);

				}else if(vec.size() == 3){

					work_3[0] = vec[0];
					work_3[1] = vec[1];
					work_3[2] = vec[2];

					calc_3(i,work_3);

				}else{

					for(int a = 0; a < 4; a++){

						work_4[a] = vec[a];
					}

					calc_4(i,work_4);
				}
			}
		}
	}

	for(int i = 0; i < N; i++){
		if(info[i].size() == 0){

			printf("-1\n");
			return 0;
		}
	}

	ans = BIG_NUM;
	recursive(0);

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}

	return 0;
}
accuracy: 1
time_ms: 4010
memory_kb: 169416
final_rank: 4

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 15
#define NUM 32768

struct Edge{
	Edge(int arg_to_country,int arg_to_city,int arg_cost){
		to_country = arg_to_country;
		to_city = arg_to_city;
		cost = arg_cost;
	}
	int to_country,to_city,cost;
};

struct INPUT{
	bool operator<(const struct INPUT &arg) const{

		return OUTER > arg.OUTER;
	}
	int index,CITY,OUTER;
};

struct Edge2{
	Edge2(int arg_to,int arg_cost){
		to = arg_to;
		cost = arg_cost;
	}
	int to,cost;
};

struct Info{
	Info(int arg_num_out,int arg_IN[4],int arg_OUT[4],int arg_COST[3],int arg_COUNT){
		num_out = arg_num_out;
		for(int i = 0; i < num_out; i++){
			IN[i] = arg_IN[i];
			OUT[i] = arg_OUT[i];
		}
		for(int i = 0; i < 3; i++){

			COST[i] = arg_COST[i];
		}
		COUNT = arg_COUNT;
	}
	int num_out,IN[4],OUT[4],COST[3],COUNT;
};

struct Data{
	void set(int arg_country,int arg_left,int arg_right){
		country = arg_country;
		left = arg_left;
		right = arg_right;
	}
	int country;
	int left,right;
};

struct DEBUG{

	int pre_state,pre_node;
};

int N,K;
int num_city[SIZE],num_outer[SIZE];
int POW[SIZE+1];
int STATE[SIZE];
int ONE[NUM][SIZE];
int DIST[SIZE][SIZE][SIZE][SIZE];
int work_dp[SIZE][NUM][SIZE];
int DP[NUM][SIZE];
int ans;
int num_STATE[SIZE+1];
int table[SIZE+1][NUM];
int LAST[SIZE+1][NUM][SIZE+1],num_LAST[SIZE+1][NUM];
int NEXT[SIZE+1][NUM][SIZE+1][SIZE+1];
int num_NEXT[SIZE+1][NUM][SIZE+1];
int NOT[NUM][SIZE+1],num_NOT[NUM];
bool used[SIZE][4][4][4][4],pair_used[SIZE][4][4];
Data DATA[SIZE];
vector<Edge> same_G[SIZE][SIZE],diff_G[SIZE][SIZE];
vector<Info> info[SIZE];
map<int,int> MAP;
INPUT input[SIZE+1];


void calc_2(int index,int work[2]){

	if(num_city[index] == 2){ //立ち寄り2回

		int IN[4] = {work[0],work[1],-1,-1};
		int OUT[4] = {work[0],work[1],-1,-1};
		int COST[3] = {0,-1,-1};

		info[index].push_back(Info(2,IN,OUT,COST,-1));

	}else{ //first入りsecond出

		do{

			int first = work[0];
			int second = work[1];

			if(work_dp[first][POW[num_city[index]]-1][second] == BIG_NUM)continue;

			int tmp_cost = work_dp[first][POW[num_city[index]]-1][second];

			int IN[4] = {first,-1,-1,-1};
			int OUT[4] = {second,-1,-1,-1};
			int COST[3] = {tmp_cost,-1,-1};

			info[index].push_back(Info(1,IN,OUT,COST,-1));

		}while(next_permutation(work,work+2));
	}
}

void calc_3(int index,int work[3]){

	if(num_city[index] == 3){ //立ち寄り3回

		int IN[4] = {work[0],work[1],work[2],-1};
		int OUT[4] = {work[0],work[1],work[2],-1};
		int COST[3] = {0,-1,-1};

		info[index].push_back(Info(3,IN,OUT,COST,-1));

	}else{ //first立ち寄り,second入りthird出

		do{
			int first = work[0];
			int second = work[1];
			int third = work[2];

			int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

			if(work_dp[second][to_state][third] < BIG_NUM){

				int IN[4] = {first,second,-1,-1};
				int OUT[4] = {first,third,-1,-1};
				int COST[3] = {work_dp[second][to_state][third],-1,-1};

				info[index].push_back(Info(2,IN,OUT,COST,-1));
			}

		}while(next_permutation(work,work+3));
	}
}

void calc_4(int index,int work[4]){

	if(num_city[index] == 4){ //立ち寄り4回

		int IN[4] = {work[0],work[1],work[2],work[3]};
		int OUT[4] = {work[0],work[1],work[2],work[3]};
		int COST[3] = {0,-1,-1};

		info[index].push_back(Info(4,IN,OUT,COST,-1));

	}else{

		do{

			int a = work[0];
			int b = work[1];
			int c = work[2];
			int d = work[3];

			//a入りb出-c入d出
			if(!used[index][c][d][a][b]){
				used[index][a][b][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[c]+POW[d]);
				int tmp_cost = BIG_NUM;

				for(int from_state = 1; from_state <= to_state; from_state++){
					if(((from_state & POW[c]) == POW[c]) ||
						((from_state & POW[d]) == POW[d]) ||
						((from_state & POW[a]) != POW[a]) ||
						((from_state & POW[b]) != POW[b]))continue;
					if(work_dp[a][from_state][b] == BIG_NUM)continue;

					int rest_state = POW[num_city[index]]-1-from_state;
					if(work_dp[c][rest_state][d] == BIG_NUM)continue;

					tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
				}

				if(tmp_cost < BIG_NUM){

					int IN[4] = {a,c,-1,-1};
					int OUT[4] = {b,d,-1,-1};
					int COST[3] = {tmp_cost,-1,-1};

					info[index].push_back(Info(2,IN,OUT,COST,-1));
				}
			}

			//a,b立ち寄り,c入d出
			if(!pair_used[index][c][d]){
				pair_used[index][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[a]+POW[b]);

				if(work_dp[c][to_state][d] < BIG_NUM){

					int IN[4] = {a,b,c,-1};
					int OUT[4] = {a,b,d,-1};
					int COST[3] = {work_dp[c][to_state][d],-1,-1};

					info[index].push_back(Info(3,IN,OUT,COST,-1));
				}
			}

		}while(next_permutation(work,work+4));
	}
}

void calc_zero(int count_outer){

	for(int left = 0; left <= 2; left++){
		int IN[4] = {left,-1,-1,-1};
		int OUT[4] = {-1,-1,-1,-1};

		int COST[3];
		for(int i = 0; i < 3; i++){

			COST[i] = -1;
		}
		for(int right = left+1; right <= 3; right++){

			COST[right-(left+1)] = work_dp[left][POW[num_city[0]]-1][right]; //left入りright出
		}

		info[0].push_back(Info(1,IN,OUT,COST,2));
	}

	int first,second,third;

	for(int loop = 0; loop < 3; loop++){
		if(loop == 0){
			first = 0;
			second = 1;
			third = 2;
		}else if(loop == 1){
			first = 1;
			second = 0;
			third = 2;
		}else{
			first = 2;
			second = 0;
			third = 1;
		}

		int to_state = (POW[num_city[0]]-1)-POW[first]; //firstを除いてTSP

		if(work_dp[second][to_state][third] < BIG_NUM){

			int IN[4] = {first,second,-1,-1};
			int OUT[4] = {first,third,-1,-1};
			int COST[3] = {work_dp[second][to_state][third],-1,-1};

			info[0].push_back(Info(2,IN,OUT,COST,-1));
		}
	}

	int a,b,c,d;
	for(int loop = 0; loop < 6; loop++){
		if(loop == 0){
			a = 0;
			b = 1;
			c = 2;
			d = 3;
		}else if(loop == 1){
			a = 0;
			b = 1;
			c = 3;
			d = 2;
		}else if(loop == 2){
			a = 0;
			b = 2;
			c = 1;
			d = 3;
		}else if(loop == 3){
			a = 0;
			b = 2;
			c = 3;
			d = 1;
		}else if(loop == 4){
			a = 0;
			b = 3;
			c = 1;
			d = 2;
		}else{ //loop == 5
			a = 0;
			b = 3;
			c = 2;
			d = 1;
		}

		//a入りb出-c入d出
		int to_state = (POW[num_city[0]]-1)-(POW[c]+POW[d]);
		int tmp_cost = BIG_NUM;

		for(int from_state = 1; from_state <= to_state; from_state++){
			if(((from_state & POW[c]) == POW[c]) ||
				((from_state & POW[d]) == POW[d]) ||
				((from_state & POW[a]) != POW[a]) ||
				((from_state & POW[b]) != POW[b]))continue;
			if(work_dp[a][from_state][b] == BIG_NUM)continue;

			int rest_state = POW[num_city[0]]-1-from_state;
			if(work_dp[c][rest_state][d] == BIG_NUM)continue;

			tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
		}

		if(tmp_cost < BIG_NUM){

			int IN[4] = {a,c,-1,-1};
			int OUT[4] = {b,d,-1,-1};
			int COST[3] = {tmp_cost,-1,-1};

			info[0].push_back(Info(2,IN,OUT,COST,-1));
		}
	}

	for(int loop = 0; loop < 6; loop++){
		if(loop == 0){
			a = 2;
			b = 3;
			c = 0;
			d = 1;
		}else if(loop == 1){
			a = 1;
			b = 3;
			c = 0;
			d = 2;
		}else if(loop == 2){
			a = 1;
			b = 2;
			c = 0;
			d = 3;
		}else if(loop == 3){
			a = 0;
			b = 3;
			c = 1;
			d = 2;
		}else if(loop == 4){
			a = 0;
			b = 2;
			c = 1;
			d = 3;
		}else{ //loop == 5
			a = 0;
			b = 1;
			c = 2;
			d = 3;
		}

		//a,b立ち寄り,c入d出
		int to_state = (POW[num_city[0]]-1)-(POW[a]+POW[b]);

		if(work_dp[c][to_state][d] < BIG_NUM){

			int IN[4] = {a,b,c,-1};
			int OUT[4] = {a,b,d,-1};
			int COST[3] = {work_dp[c][to_state][d],-1,-1};
			info[0].push_back(Info(3,IN,OUT,COST,-1));
		}
	}
}

void calc_one(){

	if(num_city[0] == 1){

		printf("0\n");
		return;
	}

	int index = 0;

	for(int state = 0; state < POW[num_city[index]]; state++){
		for(int last = 0; last < num_city[index]; last++){

			ONE[state][last] = BIG_NUM;
		}
	}

	//経路は輪になるので、スタートは0として良いはず
	ONE[POW[0]][0] = 0;

	for(int state = 1; state < POW[num_city[index]]-1; state++){
		for(int last = 0; last < num_city[index]; last++){
			if(ONE[state][last] == BIG_NUM)continue;

			for(int i = 0; i < same_G[index][last].size(); i++){

				int next_node = same_G[index][last][i].to_city;

				if(state & POW[next_node])continue;

				int next_state = state+POW[next_node];
				int next_cost = ONE[state][last]+same_G[index][last][i].cost;

				ONE[next_state][next_node] = min(ONE[next_state][next_node],next_cost);
			}
		}
	}

	int ans = BIG_NUM;
	for(int last = 0; last < num_city[index]; last++){
		if(ONE[POW[num_city[index]]-1][last] == BIG_NUM)continue;

		ans = min(ans,ONE[POW[num_city[index]]-1][last]+DIST[0][last][0][0]);
	}

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}
}
void recursive(int index){

	if(index < N){

		for(int i = 0; i < info[index].size(); i++){

			STATE[index] = i;
			recursive(index+1);
		}
		return;
	}

	//index == N
	int num_DATA = 0;
	int add = 0;

	int work_DIST[SIZE][SIZE];
	for(int i = 0; i < SIZE; i++){
		for(int k = 0; k < SIZE; k++){

			work_DIST[i][k] = BIG_NUM;
		}
	}

	for(int i = 0; i < N; i++){
		int num = STATE[i];
		if(i > 0 || info[i][num].COUNT == -1){
			add += info[i][num].COST[0];
		}
		for(int k = 0; k < info[i][num].num_out; k++){

			DATA[num_DATA++].set(i,info[i][num].IN[k],info[i][STATE[i]].OUT[k]);
		}
	}

	if(add >= ans)return;

	for(int i = 1; i < num_DATA; i++){
		for(int k = 1; k < num_DATA; k++){
			if((k == i)||(num_city[DATA[i].country] < num_outer[DATA[i].country] && DATA[i].country == DATA[k].country))continue;

			int from_country = DATA[i].country;
			int from_city = DATA[i].right;

			int to_country = DATA[k].country;
			int to_city = DATA[k].left;

			if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

			work_DIST[i][k] = DIST[from_country][from_city][to_country][to_city];
		}
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		int state = table[num_DATA][i];
		for(int k = 0; k < num_LAST[num_DATA][state]; k++){

			DP[state][LAST[num_DATA][state][k]] = BIG_NUM;
		}
	}
	for(int last = 1; last < num_DATA; last++){

		DP[POW[num_DATA]-1][last] = BIG_NUM;
	}

	for(int i = 1; i < num_DATA; i++){
		if(info[0][STATE[0]].COUNT == -1){

			for(int k = 1; k < num_DATA; k++){

				int from_country = 0;
				int from_city = DATA[0].right;

				int to_country = DATA[k].country;
				int to_city = DATA[k].left;

				if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

				DP[POW[0]|POW[k]][k] = DIST[from_country][from_city][to_country][to_city];
			}
		}else{ //国0がnum2

			int left = DATA[0].left;
			for(int right = left+1; right <= 3; right++){

				int from_country = 0;
				int from_city = right;

				for(int k = 1; k < num_DATA; k++){
					int to_country = DATA[k].country;
					int to_city = DATA[k].left;

					if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

					DP[POW[0]|POW[k]][k] = min(DP[POW[0]|POW[k]][k],DIST[from_country][from_city][to_country][to_city]+info[0][STATE[0]].COST[right-(left+1)]);
				}

			}
		}
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		int state = table[num_DATA][i];
		int max_k = num_LAST[num_DATA][state];
		for(int k = 0; k < max_k; k++){
			int last = LAST[num_DATA][state][k];
			if(DP[state][last]==BIG_NUM)continue;
			int max_a = num_NEXT[num_DATA][state][k];
			for(int a = 0; a < max_a; a++){
				int next = NEXT[num_DATA][state][k][a];
				DP[state|(1<<next)][next] = min(DP[state|(1<<next)][next],
						DP[state][last]+work_DIST[last][next]);
			}
		}
	}

	int tmp_ans = BIG_NUM;

	for(int last = 1; last < num_DATA; last++){
		if(DP[POW[num_DATA]-1][last] == BIG_NUM)continue;

		int pre_country = DATA[last].country;
		int pre_city = DATA[last].right;

		int next_country = DATA[0].country;
		int next_city = DATA[0].left;

		if(DIST[pre_country][pre_city][next_country][next_city] == BIG_NUM)continue;

		if(tmp_ans > DP[POW[num_DATA]-1][last]+
				DIST[pre_country][pre_city][next_country][next_city]){
			tmp_ans = DP[POW[num_DATA]-1][last]+
					DIST[pre_country][pre_city][next_country][next_city];
		}
	}

	if(tmp_ans < BIG_NUM){

		ans = min(ans,tmp_ans+add);
	}
}

void calc_dp(int index){

	for(int start = 0; start < num_outer[index]; start++){
		for(int state = 0; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){

				work_dp[start][state][last] = BIG_NUM;
			}
		}
	}

	for(int i = 0; i < num_outer[index]; i++){
		work_dp[i][POW[i]][i] = 0;
		for(int state = 1; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){
				if(work_dp[i][state][last] == BIG_NUM)continue;

				for(int next = 0; next < num_city[index]; next++){
					if(state & POW[next])continue;
					if(DIST[index][last][index][next] == BIG_NUM)continue;

					int next_state = state+POW[next];
					int next_cost = work_dp[i][state][last]+DIST[index][last][index][next];

					work_dp[i][next_state][next] = min(work_dp[i][next_state][next],next_cost);
				}
			}
		}
	}
}

void calc_LAST_NEXT(){

	for(int i = 2; i <= 15; i++){
		int maximum = POW[i];
		num_STATE[i] = 0;
		for(int state = 3; state <= maximum-3; state += 2){ //DATA[0]を訪問済の状態のみ列挙

			table[i][num_STATE[i]++] = state;

			num_NOT[state] = 0;
			for(int k = 1; k < i; k++){
				if(state&POW[k])continue;
				NOT[state][num_NOT[state]++] = k;
			}

			num_LAST[i][state] = 0;

			for(int last = 1; last < i; last++){
				if((state&POW[last]) == 0)continue;

				LAST[i][state][num_LAST[i][state]] = last;
				num_NEXT[i][state][num_LAST[i][state]] = 0;

				for(int next = 1; next < i; next++){
					if(next == last)continue;
					if(state&POW[next])continue;

					NEXT[i][state][num_LAST[i][state]][num_NEXT[i][state][num_LAST[i][state]]++] = next;
				}
				num_LAST[i][state]++;
			}
		}
	}
}

int main(){

	POW[0] = 1;
	for(int i = 1; i <= SIZE; i++){

		POW[i] = POW[i-1]*2;
	}

	for(int a = 0; a < SIZE; a++){
		for(int b = 0; b < SIZE; b++){
			for(int c = 0; c < SIZE; c++){
				for(int d = 0; d < SIZE; d++){
					DIST[a][b][c][d] = BIG_NUM;
				}
			}
		}
	}

	for(int i = 0; i < SIZE; i++){
		for(int a = 0; a < 4; a++){
			for(int b = 0; b < 4; b++){
				pair_used[i][a][b] = false;
				for(int c = 0; c < 4; c++){
					for(int d = 0; d < 4; d++){
						used[i][a][b][c][d] = false;
					}
				}
			}
		}
	}

	scanf("%d %d",&N,&K);

	for(int i = 0; i < N; i++){
		input[i].index = i;
		scanf("%d",&input[i].CITY);
	}

	for(int i = 0; i < N; i++){

		scanf("%d",&input[i].OUTER);
	}

	sort(input,input+N);

	for(int i = 0; i < N; i++){
		MAP[input[i].index] = i;
		num_city[i] = input[i].CITY;
		num_outer[i] = input[i].OUTER;
	}

	int from_country,from_city,to_country,to_city,cost;

	for(int i = 0; i < K; i++){

		scanf("%d %d %d %d %d",&from_country,&from_city,&to_country,&to_city,&cost);
		from_country--;
		from_city--;
		to_country--;
		to_city--;

		from_country = MAP[from_country];
		to_country = MAP[to_country];

		if(from_country == to_country){

			same_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			same_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));

		}else{

			diff_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			diff_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));
		}

		DIST[from_country][from_city][to_country][to_city] = cost;
		DIST[to_country][to_city][from_country][from_city] = cost;
	}

	if(N == 1){

		calc_one();
		return 0;
	}

	calc_LAST_NEXT();
	int start = 0;

	if(num_outer[0] == 4 && num_city[0] > 4){
		calc_dp(0);
		start = 1;
		calc_zero(num_outer[0]);
	}

	for(int i = start; i < N; i++){

		if(num_outer[i] == 1){

			int IN[4] = {0,-1,-1,-1};
			int OUT[4] = {0,-1,-1,-1};
			int COST[3] = {0,-1,-1};

			if(num_city[i] > 1){

				printf("-1\n");
				return 0;

			}else{

				info[i].push_back(Info(1,IN,OUT,COST,-1));
			}

		}else if(num_outer[i] == 2){

			calc_dp(i);

			int work[2] = {0,1};

			calc_2(i,work);

		}else if(num_outer[i] == 3){

			calc_dp(i);

			int work_2[2],work_3[3];

			for(int state = 1; state < POW[3]; state++){
				vector<int> vec;
				for(int loop = 0; loop < 3; loop++){
					if(state&POW[loop]){

						vec.push_back(loop);
					}
				}
				if(vec.size() == 1)continue;

				if(vec.size() == 2){ //国際空港を2つ使う場合

					work_2[0] = vec[0];
					work_2[1] = vec[1];

					calc_2(i,work_2);

				}else{ //国際空港を3つ使う場合

					work_3[0] = vec[0];
					work_3[1] = vec[1];
					work_3[2] = vec[2];

					calc_3(i,work_3);
				}
			}

		}else{ //num_outer[i] == 4

			calc_dp(i);

			int work_2[2],work_3[3],work_4[4];

			for(int state = 1; state < POW[4]; state++){
				vector<int> vec;
				for(int loop = 0; loop < 4; loop++){
					if(state&POW[loop]){

						vec.push_back(loop);
					}
				}
				if(vec.size() == 1)continue;

				if(vec.size() == 2){

					work_2[0] = vec[0];
					work_2[1] = vec[1];

					calc_2(i,work_2);

				}else if(vec.size() == 3){

					work_3[0] = vec[0];
					work_3[1] = vec[1];
					work_3[2] = vec[2];

					calc_3(i,work_3);

				}else{

					for(int a = 0; a < 4; a++){

						work_4[a] = vec[a];
					}

					calc_4(i,work_4);
				}
			}
		}
	}

	for(int i = 0; i < N; i++){
		if(info[i].size() == 0){

			printf("-1\n");
			return 0;
		}
	}

	ans = BIG_NUM;
	recursive(0);

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}

	double last = time(NULL);

	return 0;
}
accuracy: 0.8
time_ms: 480
memory_kb: 87708
final_rank: 10

code_snippet: #include<bits/stdc++.h>
/*m(_ _)m申し訳ございません...*/
#pragma GCC target("avx")
#pragma GCC optimize("O3")
/*m(_ _)m申し訳ございません...*/
typedef long long int ll;
typedef unsigned long long int ull;
//#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 15
#define NUM 32768

struct Edge{
	Edge(int arg_to_country,int arg_to_city,int arg_cost){
		to_country = arg_to_country;
		to_city = arg_to_city;
		cost = arg_cost;
	}
	int to_country,to_city,cost;
};

struct Edge2{
	Edge2(int arg_to,int arg_cost){
		to = arg_to;
		cost = arg_cost;
	}
	int to,cost;
};

struct Info{
	Info(int arg_num_out,int arg_IN[4],int arg_OUT[4],int arg_cost){
		num_out = arg_num_out;
		for(int i = 0; i < num_out; i++){
			IN[i] = arg_IN[i];
			OUT[i] = arg_OUT[i];
		}
		cost = arg_cost;
	}
	int num_out,IN[4],OUT[4],cost;
};

struct Data{
	void set(int arg_country,int arg_left,int arg_right){
		country = arg_country;
		left = arg_left;
		right = arg_right;
	}
	int country;
	int left,right;
};

struct DEBUG{

	int pre_state,pre_node;
};

const int BIG_NUM = 2000000000;
int N,K;
int num_city[SIZE],num_outer[SIZE];
int POW[SIZE+1];
int STATE[SIZE];
int ONE[NUM][SIZE];
int DIST[SIZE][SIZE][SIZE][SIZE];
int work_dp[SIZE][NUM][SIZE];
int DP[NUM][SIZE];
int ans;
int num_STATE[SIZE+1];
int table[SIZE+1][NUM];
int LAST[SIZE+1][NUM][SIZE+1],num_LAST[SIZE+1][NUM];
int NEXT[SIZE+1][NUM][SIZE+1][SIZE+1];
int num_NEXT[SIZE+1][NUM][SIZE+1];
int NOT[NUM][SIZE+1],num_NOT[NUM];
bool used[SIZE][4][4][4][4],pair_used[SIZE][4][4];
Data DATA[SIZE];
vector<Edge> same_G[SIZE][SIZE],diff_G[SIZE][SIZE];
vector<Info> info[SIZE];


void calc_2(int index,int work[2],bool is_maximum){

	if(num_city[index] == 2){ //立ち寄り2回

		int IN[4] = {work[0],work[1],-1,-1};
		int OUT[4] = {work[0],work[1],-1,-1};

		info[index].push_back(Info(2,IN,OUT,0));

	}else{ //first入りsecond出

		if(is_maximum){

			int first = work[0];
			int second = work[1];

			if(work_dp[first][POW[num_city[index]]-1][second] == BIG_NUM)return;

			int tmp_cost = work_dp[first][POW[num_city[index]]-1][second];

			int IN[4] = {first,-1,-1,-1};
			int OUT[4] = {second,-1,-1,-1};

			info[index].push_back(Info(1,IN,OUT,tmp_cost));

			return;
		}

		do{

			int first = work[0];
			int second = work[1];

			if(work_dp[first][POW[num_city[index]]-1][second] == BIG_NUM)continue;

			int tmp_cost = work_dp[first][POW[num_city[index]]-1][second];

			int IN[4] = {first,-1,-1,-1};
			int OUT[4] = {second,-1,-1,-1};

			info[index].push_back(Info(1,IN,OUT,tmp_cost));

		}while(next_permutation(work,work+2));
	}
}

void calc_3(int index,int work[3],bool is_maximum){

	if(num_city[index] == 3){ //立ち寄り3回

		int IN[4] = {work[0],work[1],work[2],-1};
		int OUT[4] = {work[0],work[1],work[2],-1};

		info[index].push_back(Info(3,IN,OUT,0));

	}else{ //first立ち寄り,second入りthird出

		if(is_maximum){

			int first,second,third;

			for(int loop = 0; loop < 3; loop++){
				if(loop == 0){
					first = work[0];
					second = work[1];
					third = work[2];
				}else if(loop == 1){
					first = work[1];
					second = work[0];
					third = work[2];
				}else{
					first = work[2];
					second = work[0];
					third = work[1];
				}

				int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

				if(work_dp[second][to_state][third] < BIG_NUM){

					int IN[4] = {first,second,-1,-1};
					int OUT[4] = {first,third,-1,-1};

					info[index].push_back(Info(2,IN,OUT,work_dp[second][to_state][third]));
				}
			}
			return;
		}

		do{
			int first = work[0];
			int second = work[1];
			int third = work[2];

			int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

			if(work_dp[second][to_state][third] < BIG_NUM){

				int IN[4] = {first,second,-1,-1};
				int OUT[4] = {first,third,-1,-1};

				info[index].push_back(Info(2,IN,OUT,work_dp[second][to_state][third]));
			}

		}while(next_permutation(work,work+3));
	}
}

void calc_4(int index,int work[4],bool is_maximum){

	if(num_city[index] == 4){ //立ち寄り4回

		int IN[4] = {work[0],work[1],work[2],work[3]};
		int OUT[4] = {work[0],work[1],work[2],work[3]};

		info[index].push_back(Info(4,IN,OUT,0));

	}else{

		if(is_maximum){

			do{

				int a = work[0];
				int b = work[1];
				int c = work[2];
				int d = work[3];

				//a入りb出-c入d出
				if(a<b&&!used[index][c][d][a][b]){
					used[index][a][b][c][d] = true;

					int to_state = (POW[num_city[index]]-1)-(POW[c]+POW[d]);
					int tmp_cost = BIG_NUM;

					for(int from_state = 1; from_state <= to_state; from_state++){
						if(((from_state & POW[c]) == POW[c]) ||
							((from_state & POW[d]) == POW[d]) ||
							((from_state & POW[a]) != POW[a]) ||
							((from_state & POW[b]) != POW[b]))continue;
						if(work_dp[a][from_state][b] == BIG_NUM)continue;

						int rest_state = POW[num_city[index]]-1-from_state;
						if(work_dp[c][rest_state][d] == BIG_NUM)continue;

						tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
					}

					if(tmp_cost < BIG_NUM){

						int IN[4] = {a,c,-1,-1};
						int OUT[4] = {b,d,-1,-1};

						info[index].push_back(Info(2,IN,OUT,tmp_cost));
					}
				}

				//a,b立ち寄り,c入d出
				if(c<d&&!pair_used[index][c][d]){
					pair_used[index][c][d] = true;

					int to_state = (POW[num_city[index]]-1)-(POW[a]+POW[b]);

					if(work_dp[c][to_state][d] < BIG_NUM){

						int IN[4] = {a,b,c,-1};
						int OUT[4] = {a,b,d,-1};

						info[index].push_back(Info(3,IN,OUT,work_dp[c][to_state][d]));
					}
				}

			}while(next_permutation(work,work+4));

			return;
		}

		do{

			int a = work[0];
			int b = work[1];
			int c = work[2];
			int d = work[3];

			//a入りb出-c入d出
			if(!used[index][c][d][a][b]){
				used[index][a][b][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[c]+POW[d]);
				int tmp_cost = BIG_NUM;

				for(int from_state = 1; from_state <= to_state; from_state++){
					if(((from_state & POW[c]) == POW[c]) ||
						((from_state & POW[d]) == POW[d]) ||
						((from_state & POW[a]) != POW[a]) ||
						((from_state & POW[b]) != POW[b]))continue;
					if(work_dp[a][from_state][b] == BIG_NUM)continue;

					int rest_state = POW[num_city[index]]-1-from_state;
					if(work_dp[c][rest_state][d] == BIG_NUM)continue;

					tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
				}

				if(tmp_cost < BIG_NUM){

					int IN[4] = {a,c,-1,-1};
					int OUT[4] = {b,d,-1,-1};

					info[index].push_back(Info(2,IN,OUT,tmp_cost));
				}
			}

			//a,b立ち寄り,c入d出
			if(!pair_used[index][c][d]){
				pair_used[index][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[a]+POW[b]);

				if(work_dp[c][to_state][d] < BIG_NUM){

					int IN[4] = {a,b,c,-1};
					int OUT[4] = {a,b,d,-1};

					info[index].push_back(Info(3,IN,OUT,work_dp[c][to_state][d]));
				}
			}

		}while(next_permutation(work,work+4));
	}
}


void calc_one(){

	if(num_city[0] == 1){

		printf("0\n");
		return;
	}

	int index = 0;

	for(int state = 0; state < POW[num_city[index]]; state++){
		for(int last = 0; last < num_city[index]; last++){

			ONE[state][last] = BIG_NUM;
		}
	}

	//経路は輪になるので、スタートは0として良いはず
	ONE[POW[0]][0] = 0;

	for(int state = 1; state < POW[num_city[index]]-1; state++){
		for(int last = 0; last < num_city[index]; last++){
			if(ONE[state][last] == BIG_NUM)continue;

			for(int i = 0; i < same_G[index][last].size(); i++){

				int next_node = same_G[index][last][i].to_city;

				if(state & POW[next_node])continue;

				int next_state = state+POW[next_node];
				int next_cost = ONE[state][last]+same_G[index][last][i].cost;

				ONE[next_state][next_node] = min(ONE[next_state][next_node],next_cost);
			}
		}
	}

	int ans = BIG_NUM;
	for(int last = 0; last < num_city[index]; last++){
		if(ONE[POW[num_city[index]]-1][last] == BIG_NUM)continue;

		ans = min(ans,ONE[POW[num_city[index]]-1][last]+DIST[0][last][0][0]);
	}

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}
}
void recursive(int index){

	if(index < N){

		for(int i = 0; i < info[index].size(); i++){

			STATE[index] = i;
			recursive(index+1);
		}
		return;
	}

	//index == N
	int num_DATA = 0;
	int add = 0;

	int work_DIST[SIZE][SIZE];
	for(int i = 0; i < SIZE; i++){
		for(int k = 0; k < SIZE; k++){

			work_DIST[i][k] = BIG_NUM;
		}
	}

	for(int i = 0; i < N; i++){
		add += info[i][STATE[i]].cost;
		for(int k = 0; k < info[i][STATE[i]].num_out; k++){

			DATA[num_DATA++].set(i,info[i][STATE[i]].IN[k],info[i][STATE[i]].OUT[k]);
		}
	}

	if(add >= ans)return;

	for(int i = 0; i < num_DATA; i++){
		for(int k = 1; k < num_DATA; k++){
			if((k == i)||(num_city[DATA[i].country] < num_outer[DATA[i].country] && DATA[i].country == DATA[k].country))continue;

			int from_country = DATA[i].country;
			int from_city = DATA[i].right;

			int to_country = DATA[k].country;
			int to_city = DATA[k].left;

			if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

			work_DIST[i][k] = DIST[from_country][from_city][to_country][to_city];
		}
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		for(int k = 0; k < num_LAST[num_DATA][table[num_DATA][i]]; k++){

			DP[table[num_DATA][i]][LAST[num_DATA][table[num_DATA][i]][k]] = BIG_NUM;
		}
	}
	for(int last = 1; last < num_DATA; last++){

		DP[POW[num_DATA]-1][last] = BIG_NUM;
	}

	for(int i = 1; i < num_DATA; i++){
		if(work_DIST[0][i] == BIG_NUM)continue;

		DP[POW[0]+POW[i]][i] = work_DIST[0][i];
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		int state = table[num_DATA][i];
		for(int k = 0; k < num_LAST[num_DATA][state]; k++){
			int last = LAST[num_DATA][state][k];
			if(DP[state][last] == BIG_NUM)continue;

			for(int a = 0; a < num_NEXT[num_DATA][state][k]; a++){

				int next = NEXT[num_DATA][state][k][a];
				DP[state|(1<<next)][next] = min(DP[state|(1<<next)][next],
						DP[state][last]+work_DIST[last][next]);
			}
		}
	}

	int tmp_ans = BIG_NUM;

	for(int last = 1; last < num_DATA; last++){
		if(DP[POW[num_DATA]-1][last] == BIG_NUM)continue;

		int pre_country = DATA[last].country;
		int pre_city = DATA[last].right;

		int next_country = DATA[0].country;
		int next_city = DATA[0].left;

		if(DIST[pre_country][pre_city][next_country][next_city] == BIG_NUM)continue;

		if(tmp_ans > DP[POW[num_DATA]-1][last]+
				DIST[pre_country][pre_city][next_country][next_city]){
			tmp_ans = DP[POW[num_DATA]-1][last]+
					DIST[pre_country][pre_city][next_country][next_city];
		}
	}

	if(tmp_ans < BIG_NUM){

		ans = min(ans,tmp_ans+add);
	}
}

void calc_dp(int index){

	for(int start = 0; start < num_outer[index]; start++){
		for(int state = 0; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){

				work_dp[start][state][last] = BIG_NUM;
			}
		}
	}

	for(int i = 0; i < num_outer[index]; i++){
		work_dp[i][POW[i]][i] = 0;
		for(int state = 1; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){
				if(work_dp[i][state][last] == BIG_NUM)continue;

				for(int next = 0; next < num_city[index]; next++){
					if(state & POW[next])continue;
					if(DIST[index][last][index][next] == BIG_NUM)continue;

					int next_state = state+POW[next];
					int next_cost = work_dp[i][state][last]+DIST[index][last][index][next];

					work_dp[i][next_state][next] = min(work_dp[i][next_state][next],next_cost);
				}
			}
		}
	}
}

void calc_LAST_NEXT(){

	for(int i = 2; i <= 15; i++){
		int maximum = POW[i];
		num_STATE[i] = 0;
		for(int state = 3; state <= maximum-3; state += 2){ //DATA[0]を訪問済の状態のみ列挙

			table[i][num_STATE[i]++] = state;

			num_NOT[state] = 0;
			for(int k = 1; k < i; k++){
				if(state&POW[k])continue;
				NOT[state][num_NOT[state]++] = k;
			}

			num_LAST[i][state] = 0;

			for(int last = 1; last < i; last++){
				if((state&POW[last]) == 0)continue;

				LAST[i][state][num_LAST[i][state]] = last;
				num_NEXT[i][state][num_LAST[i][state]] = 0;

				for(int next = 1; next < i; next++){
					if(next == last)continue;
					if(state&POW[next])continue;

					NEXT[i][state][num_LAST[i][state]][num_NEXT[i][state][num_LAST[i][state]]++] = next;
				}
				num_LAST[i][state]++;
			}
		}
	}
}

int main(){

	POW[0] = 1;
	for(int i = 1; i <= SIZE; i++){

		POW[i] = POW[i-1]*2;
	}

	for(int a = 0; a < SIZE; a++){
		for(int b = 0; b < SIZE; b++){
			for(int c = 0; c < SIZE; c++){
				for(int d = 0; d < SIZE; d++){
					DIST[a][b][c][d] = BIG_NUM;
				}
			}
		}
	}

	for(int i = 0; i < SIZE; i++){
		for(int a = 0; a < 4; a++){
			for(int b = 0; b < 4; b++){
				pair_used[i][a][b] = false;
				for(int c = 0; c < 4; c++){
					for(int d = 0; d < 4; d++){
						used[i][a][b][c][d] = false;
					}
				}
			}
		}
	}

	scanf("%d %d",&N,&K);

	for(int i = 0; i < N; i++){

		scanf("%d",&num_city[i]);
	}

	int max_index = -1;
	int max_outer = 0;

	for(int i = 0; i < N; i++){

		scanf("%d",&num_outer[i]);
		if(max_outer < num_outer[i]){
			max_outer = num_outer[i];
			max_index = i;
		}
	}

	int from_country,from_city,to_country,to_city,cost;

	for(int i = 0; i < K; i++){

		scanf("%d %d %d %d %d",&from_country,&from_city,&to_country,&to_city,&cost);
		from_country--;
		from_city--;
		to_country--;
		to_city--;

		if(from_country == to_country){

			same_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			same_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));

		}else{

			diff_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			diff_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));
		}

		DIST[from_country][from_city][to_country][to_city] = cost;
		DIST[to_country][to_city][from_country][from_city] = cost;
	}

	if(N == 1){

		calc_one();
		return 0;
	}

	calc_LAST_NEXT();

	for(int i = 0; i < N; i++){

		if(num_outer[i] == 1){

			int IN[4] = {0,-1,-1,-1};
			int OUT[4] = {0,-1,-1,-1};

			if(num_city[i] > 1){

				printf("-1\n");
				return 0;

			}else{

				info[i].push_back(Info(1,IN,OUT,0));
			}

		}else if(num_outer[i] == 2){

			calc_dp(i);

			int work[2] = {0,1};

			calc_2(i,work,i==max_index);

		}else if(num_outer[i] == 3){

			calc_dp(i);

			int work_2[2],work_3[3];

			for(int state = 1; state < POW[3]; state++){
				vector<int> vec;
				for(int loop = 0; loop < 3; loop++){
					if(state&POW[loop]){

						vec.push_back(loop);
					}
				}
				if(vec.size() == 1)continue;

				if(vec.size() == 2){ //国際空港を2つ使う場合

					work_2[0] = vec[0];
					work_2[1] = vec[1];

					calc_2(i,work_2,i==max_index);

				}else{ //国際空港を3つ使う場合

					work_3[0] = vec[0];
					work_3[1] = vec[1];
					work_3[2] = vec[2];

					calc_3(i,work_3,i==max_index);
				}
			}

		}else{ //num_outer[i] == 4

			calc_dp(i);

			int work_2[2],work_3[3],work_4[4];

			for(int state = 1; state < POW[4]; state++){
				vector<int> vec;
				for(int loop = 0; loop < 4; loop++){
					if(state&POW[loop]){

						vec.push_back(loop);
					}
				}
				if(vec.size() == 1)continue;

				if(vec.size() == 2){

					work_2[0] = vec[0];
					work_2[1] = vec[1];

					calc_2(i,work_2,i==max_index);

				}else if(vec.size() == 3){

					work_3[0] = vec[0];
					work_3[1] = vec[1];
					work_3[2] = vec[2];

					calc_3(i,work_3,i==max_index);

				}else{

					for(int a = 0; a < 4; a++){

						work_4[a] = vec[a];
					}

					calc_4(i,work_4,i==max_index);
				}
			}
		}
	}

	for(int i = 0; i < N; i++){
		if(info[i].size() == 0){

			printf("-1\n");
			return 0;
		}
	}

	ans = BIG_NUM;
	recursive(0);

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}

	return 0;
}
accuracy: 1
time_ms: 4460
memory_kb: 169468
final_rank: 6

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 15
#define NUM 32768

struct Edge{
	Edge(int arg_to_country,int arg_to_city,int arg_cost){
		to_country = arg_to_country;
		to_city = arg_to_city;
		cost = arg_cost;
	}
	int to_country,to_city,cost;
};

struct Edge2{
	Edge2(int arg_to,int arg_cost){
		to = arg_to;
		cost = arg_cost;
	}
	int to,cost;
};

struct Info{
	Info(int arg_num_out,int arg_IN[4],int arg_OUT[4],int arg_cost){
		num_out = arg_num_out;
		for(int i = 0; i < num_out; i++){
			IN[i] = arg_IN[i];
			OUT[i] = arg_OUT[i];
		}
		cost = arg_cost;
	}
	int num_out,IN[4],OUT[4],cost;
};

struct Data{
	void set(int arg_country,int arg_left,int arg_right){
		country = arg_country;
		left = arg_left;
		right = arg_right;
	}
	int country;
	int left,right;
};

struct DEBUG{

	int pre_state,pre_node;
};

int N,K;
int num_city[SIZE],num_outer[SIZE];
int POW[SIZE+1];
int STATE[SIZE];
int ONE[NUM][SIZE];
int DIST[SIZE][SIZE][SIZE][SIZE];
int work_dp[SIZE][NUM][SIZE];
int DP[NUM][SIZE];
int ans;
int num_STATE[SIZE+1];
int table[SIZE+1][NUM];
int LAST[SIZE+1][NUM][SIZE+1],num_LAST[SIZE+1][NUM];
int NEXT[SIZE+1][NUM][SIZE+1][SIZE+1];
int num_NEXT[SIZE+1][NUM][SIZE+1];
int NOT[NUM][SIZE+1],num_NOT[NUM];
bool used[SIZE][4][4][4][4],pair_used[SIZE][4][4];
Data DATA[SIZE];
vector<Edge> same_G[SIZE][SIZE],diff_G[SIZE][SIZE];
vector<Info> info[SIZE];


void calc_2(int index,int work[2],bool is_first){

	if(num_city[index] == 2){ //立ち寄り2回

		int IN[4] = {work[0],work[1],-1,-1};
		int OUT[4] = {work[0],work[1],-1,-1};

		info[index].push_back(Info(2,IN,OUT,0));

	}else{ //first入りsecond出

		if(is_first){

			int first = work[0];
			int second = work[1];

			if(work_dp[first][POW[num_city[index]]-1][second] == BIG_NUM)return;

			int tmp_cost = work_dp[first][POW[num_city[index]]-1][second];

			int IN[4] = {first,-1,-1,-1};
			int OUT[4] = {second,-1,-1,-1};

			info[index].push_back(Info(1,IN,OUT,tmp_cost));

			return;
		}

		do{

			int first = work[0];
			int second = work[1];

			if(work_dp[first][POW[num_city[index]]-1][second] == BIG_NUM)continue;

			int tmp_cost = work_dp[first][POW[num_city[index]]-1][second];

			int IN[4] = {first,-1,-1,-1};
			int OUT[4] = {second,-1,-1,-1};

			info[index].push_back(Info(1,IN,OUT,tmp_cost));

		}while(next_permutation(work,work+2));
	}
}

void calc_3(int index,int work[3],bool is_first){

	if(num_city[index] == 3){ //立ち寄り3回

		int IN[4] = {work[0],work[1],work[2],-1};
		int OUT[4] = {work[0],work[1],work[2],-1};

		info[index].push_back(Info(3,IN,OUT,0));

	}else{ //first立ち寄り,second入りthird出

		if(is_first){

			int first,second,third;

			for(int loop = 0; loop < 3; loop++){
				if(loop == 0){
					first = work[0];
					second = work[1];
					third = work[2];
				}else if(loop == 1){
					first = work[1];
					second = work[0];
					third = work[2];
				}else{
					first = work[2];
					second = work[0];
					third = work[1];
				}

				int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

				if(work_dp[second][to_state][third] < BIG_NUM){

					int IN[4] = {first,second,-1,-1};
					int OUT[4] = {first,third,-1,-1};

					info[index].push_back(Info(2,IN,OUT,work_dp[second][to_state][third]));
				}
			}
			return;
		}

		do{
			int first = work[0];
			int second = work[1];
			int third = work[2];

			int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

			if(work_dp[second][to_state][third] < BIG_NUM){

				int IN[4] = {first,second,-1,-1};
				int OUT[4] = {first,third,-1,-1};

				info[index].push_back(Info(2,IN,OUT,work_dp[second][to_state][third]));
			}

		}while(next_permutation(work,work+3));
	}
}

void calc_4(int index,int work[4],bool is_first){

	if(num_city[index] == 4){ //立ち寄り4回

		int IN[4] = {work[0],work[1],work[2],work[3]};
		int OUT[4] = {work[0],work[1],work[2],work[3]};

		info[index].push_back(Info(4,IN,OUT,0));

	}else{

		if(is_first){

			do{

				int a = work[0];
				int b = work[1];
				int c = work[2];
				int d = work[3];

				//a入りb出-c入d出
				if(a<b&&!used[index][c][d][a][b]){
					used[index][a][b][c][d] = true;

					int to_state = (POW[num_city[index]]-1)-(POW[c]+POW[d]);
					int tmp_cost = BIG_NUM;

					for(int from_state = 1; from_state <= to_state; from_state++){
						if(((from_state & POW[c]) == POW[c]) ||
							((from_state & POW[d]) == POW[d]) ||
							((from_state & POW[a]) != POW[a]) ||
							((from_state & POW[b]) != POW[b]))continue;
						if(work_dp[a][from_state][b] == BIG_NUM)continue;

						int rest_state = POW[num_city[index]]-1-from_state;
						if(work_dp[c][rest_state][d] == BIG_NUM)continue;

						tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
					}

					if(tmp_cost < BIG_NUM){

						int IN[4] = {a,c,-1,-1};
						int OUT[4] = {b,d,-1,-1};

						info[index].push_back(Info(2,IN,OUT,tmp_cost));
					}
				}

				//a,b立ち寄り,c入d出
				if(c<d&&!pair_used[index][c][d]){
					pair_used[index][c][d] = true;

					int to_state = (POW[num_city[index]]-1)-(POW[a]+POW[b]);

					if(work_dp[c][to_state][d] < BIG_NUM){

						int IN[4] = {a,b,c,-1};
						int OUT[4] = {a,b,d,-1};

						info[index].push_back(Info(3,IN,OUT,work_dp[c][to_state][d]));
					}
				}

			}while(next_permutation(work,work+4));

			return;
		}

		do{

			int a = work[0];
			int b = work[1];
			int c = work[2];
			int d = work[3];

			//a入りb出-c入d出
			if(!used[index][c][d][a][b]){
				used[index][a][b][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[c]+POW[d]);
				int tmp_cost = BIG_NUM;

				for(int from_state = 1; from_state <= to_state; from_state++){
					if(((from_state & POW[c]) == POW[c]) ||
						((from_state & POW[d]) == POW[d]) ||
						((from_state & POW[a]) != POW[a]) ||
						((from_state & POW[b]) != POW[b]))continue;
					if(work_dp[a][from_state][b] == BIG_NUM)continue;

					int rest_state = POW[num_city[index]]-1-from_state;
					if(work_dp[c][rest_state][d] == BIG_NUM)continue;

					tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
				}

				if(tmp_cost < BIG_NUM){

					int IN[4] = {a,c,-1,-1};
					int OUT[4] = {b,d,-1,-1};

					info[index].push_back(Info(2,IN,OUT,tmp_cost));
				}
			}

			//a,b立ち寄り,c入d出
			if(!pair_used[index][c][d]){
				pair_used[index][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[a]+POW[b]);

				if(work_dp[c][to_state][d] < BIG_NUM){

					int IN[4] = {a,b,c,-1};
					int OUT[4] = {a,b,d,-1};

					info[index].push_back(Info(3,IN,OUT,work_dp[c][to_state][d]));
				}
			}

		}while(next_permutation(work,work+4));
	}
}

void calc_one(){

	if(num_city[0] == 1){

		printf("0\n");
		return;
	}

	int index = 0;

	for(int state = 0; state < POW[num_city[index]]; state++){
		for(int last = 0; last < num_city[index]; last++){

			ONE[state][last] = BIG_NUM;
		}
	}

	//経路は輪になるので、スタートは0として良いはず
	ONE[POW[0]][0] = 0;

	for(int state = 1; state < POW[num_city[index]]-1; state++){
		for(int last = 0; last < num_city[index]; last++){
			if(ONE[state][last] == BIG_NUM)continue;

			for(int i = 0; i < same_G[index][last].size(); i++){

				int next_node = same_G[index][last][i].to_city;

				if(state & POW[next_node])continue;

				int next_state = state+POW[next_node];
				int next_cost = ONE[state][last]+same_G[index][last][i].cost;

				ONE[next_state][next_node] = min(ONE[next_state][next_node],next_cost);
			}
		}
	}

	int ans = BIG_NUM;
	for(int last = 0; last < num_city[index]; last++){
		if(ONE[POW[num_city[index]]-1][last] == BIG_NUM)continue;

		ans = min(ans,ONE[POW[num_city[index]]-1][last]+DIST[0][last][0][0]);
	}

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}
}
void recursive(int index){

	if(index < N){

		for(int i = 0; i < info[index].size(); i++){

			STATE[index] = i;
			recursive(index+1);
		}
		return;
	}

	//index == N
	int num_DATA = 0;
	int add = 0;

	int work_DIST[SIZE][SIZE];
	for(int i = 0; i < SIZE; i++){
		for(int k = 0; k < SIZE; k++){

			work_DIST[i][k] = BIG_NUM;
		}
	}

	for(int i = 0; i < N; i++){
		add += info[i][STATE[i]].cost;
		for(int k = 0; k < info[i][STATE[i]].num_out; k++){

			DATA[num_DATA++].set(i,info[i][STATE[i]].IN[k],info[i][STATE[i]].OUT[k]);
		}
	}

	if(add >= ans)return;

	for(int i = 0; i < num_DATA; i++){
		for(int k = 1; k < num_DATA; k++){
			if(k == i || DATA[i].country == DATA[k].country)continue;

			int from_country = DATA[i].country;
			int from_city = DATA[i].right;

			int to_country = DATA[k].country;
			int to_city = DATA[k].left;

			if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

			work_DIST[i][k] = DIST[from_country][from_city][to_country][to_city];
		}
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		for(int k = 0; k < num_LAST[num_DATA][table[num_DATA][i]]; k++){

			DP[table[num_DATA][i]][LAST[num_DATA][table[num_DATA][i]][k]] = BIG_NUM;
		}
	}
	for(int last = 1; last < num_DATA; last++){

		DP[POW[num_DATA]-1][last] = BIG_NUM;
	}

	for(int i = 1; i < num_DATA; i++){
		if(work_DIST[0][i] == BIG_NUM)continue;

		DP[POW[0]+POW[i]][i] = work_DIST[0][i];
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		for(int k = 0; k < num_LAST[num_DATA][table[num_DATA][i]]; k++){
			int last = LAST[num_DATA][table[num_DATA][i]][k];
			if(DP[table[num_DATA][i]][last] == BIG_NUM)continue;

			for(int a = 0; a < num_NEXT[num_DATA][table[num_DATA][i]][k]; a++){

				int next = NEXT[num_DATA][table[num_DATA][i]][k][a];
				if(work_DIST[last][next] == BIG_NUM)continue;
				DP[table[num_DATA][i]+POW[next]][next] = min(DP[table[num_DATA][i]+POW[next]][next],
						DP[table[num_DATA][i]][last]+work_DIST[last][next]);
			}
		}
	}

	int tmp_ans = BIG_NUM;

	for(int last = 1; last < num_DATA; last++){
		if(DP[POW[num_DATA]-1][last] == BIG_NUM)continue;

		int pre_country = DATA[last].country;
		int pre_city = DATA[last].right;

		int next_country = DATA[0].country;
		int next_city = DATA[0].left;

		if(DIST[pre_country][pre_city][next_country][next_city] == BIG_NUM)continue;

		if(tmp_ans > DP[POW[num_DATA]-1][last]+
				DIST[pre_country][pre_city][next_country][next_city]){
			tmp_ans = DP[POW[num_DATA]-1][last]+
					DIST[pre_country][pre_city][next_country][next_city];
		}
	}

	if(tmp_ans < BIG_NUM){

		ans = min(ans,tmp_ans+add);
	}
}

void calc_dp(int index){

	for(int start = 0; start < num_outer[index]; start++){
		for(int state = 0; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){

				work_dp[start][state][last] = BIG_NUM;
			}
		}
	}

	for(int i = 0; i < num_outer[index]; i++){
		work_dp[i][POW[i]][i] = 0;
		for(int state = 1; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){
				if(work_dp[i][state][last] == BIG_NUM)continue;

				for(int next = 0; next < num_city[index]; next++){
					if(state & POW[next])continue;
					if(DIST[index][last][index][next] == BIG_NUM)continue;

					int next_state = state+POW[next];
					int next_cost = work_dp[i][state][last]+DIST[index][last][index][next];

					work_dp[i][next_state][next] = min(work_dp[i][next_state][next],next_cost);
				}
			}
		}
	}
}

void calc_LAST_NEXT(){

	for(int i = 2; i <= 15; i++){
		int maximum = POW[i];
		num_STATE[i] = 0;
		for(int state = 3; state <= maximum-3; state += 2){ //DATA[0]を訪問済の状態のみ列挙

			table[i][num_STATE[i]++] = state;

			num_NOT[state] = 0;
			for(int k = 1; k < i; k++){
				if(state&POW[k])continue;
				NOT[state][num_NOT[state]++] = k;
			}

			num_LAST[i][state] = 0;

			for(int last = 1; last < i; last++){
				if((state&POW[last]) == 0)continue;

				LAST[i][state][num_LAST[i][state]] = last;
				num_NEXT[i][state][num_LAST[i][state]] = 0;

				for(int next = 1; next < i; next++){
					if(next == last)continue;
					if(state&POW[next])continue;

					NEXT[i][state][num_LAST[i][state]][num_NEXT[i][state][num_LAST[i][state]]++] = next;
				}
				num_LAST[i][state]++;
			}
		}
	}
}

int main(){

	POW[0] = 1;
	for(int i = 1; i <= SIZE; i++){

		POW[i] = POW[i-1]*2;
	}

	for(int a = 0; a < SIZE; a++){
		for(int b = 0; b < SIZE; b++){
			for(int c = 0; c < SIZE; c++){
				for(int d = 0; d < SIZE; d++){
					DIST[a][b][c][d] = BIG_NUM;
				}
			}
		}
	}

	for(int i = 0; i < SIZE; i++){
		for(int a = 0; a < 4; a++){
			for(int b = 0; b < 4; b++){
				pair_used[i][a][b] = false;
				for(int c = 0; c < 4; c++){
					for(int d = 0; d < 4; d++){
						used[i][a][b][c][d] = false;
					}
				}
			}
		}
	}

	scanf("%d %d",&N,&K);

	for(int i = 0; i < N; i++){

		scanf("%d",&num_city[i]);
	}
	for(int i = 0; i < N; i++){

		scanf("%d",&num_outer[i]);
	}

	int from_country,from_city,to_country,to_city,cost;

	for(int i = 0; i < K; i++){

		scanf("%d %d %d %d %d",&from_country,&from_city,&to_country,&to_city,&cost);
		from_country--;
		from_city--;
		to_country--;
		to_city--;

		if(from_country == to_country){

			same_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			same_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));

		}else{

			diff_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			diff_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));
		}

		DIST[from_country][from_city][to_country][to_city] = cost;
		DIST[to_country][to_city][from_country][from_city] = cost;
	}

	if(N == 1){

		calc_one();
		return 0;
	}

	calc_LAST_NEXT();

	for(int i = 0; i < N; i++){

		if(num_outer[i] == 1){

			int IN[4] = {0,-1,-1,-1};
			int OUT[4] = {0,-1,-1,-1};

			if(num_city[i] > 1){

				printf("-1\n");
				return 0;

			}else{

				info[i].push_back(Info(1,IN,OUT,0));
			}

		}else if(num_outer[i] == 2){

			calc_dp(i);

			int work[2] = {0,1};

			calc_2(i,work,i==0);

		}else if(num_outer[i] == 3){

			calc_dp(i);

			int work_2[2],work_3[3];

			for(int state = 1; state < POW[3]; state++){
				vector<int> vec;
				for(int loop = 0; loop < 3; loop++){
					if(state&POW[loop]){

						vec.push_back(loop);
					}
				}
				if(vec.size() == 1)continue;

				if(vec.size() == 2){ //国際空港を2つ使う場合

					work_2[0] = vec[0];
					work_2[1] = vec[1];

					calc_2(i,work_2,i==0);

				}else{ //国際空港を3つ使う場合

					work_3[0] = vec[0];
					work_3[1] = vec[1];
					work_3[2] = vec[2];

					calc_3(i,work_3,i==0);
				}
			}

		}else{ //num_outer[i] == 4

			calc_dp(i);

			int work_2[2],work_3[3],work_4[4];

			for(int state = 1; state < POW[4]; state++){
				vector<int> vec;
				for(int loop = 0; loop < 4; loop++){
					if(state&POW[loop]){

						vec.push_back(loop);
					}
				}
				if(vec.size() == 1)continue;

				if(vec.size() == 2){

					work_2[0] = vec[0];
					work_2[1] = vec[1];

					calc_2(i,work_2,i==0);

				}else if(vec.size() == 3){

					work_3[0] = vec[0];
					work_3[1] = vec[1];
					work_3[2] = vec[2];

					calc_3(i,work_3,i==0);

				}else{

					for(int a = 0; a < 4; a++){

						work_4[a] = vec[a];
					}

					calc_4(i,work_4,i==0);
				}
			}
		}
	}

	for(int i = 0; i < N; i++){
		if(info[i].size() == 0){

			printf("-1\n");
			return 0;
		}
	}

	ans = BIG_NUM;
	recursive(0);

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}

	return 0;
}
accuracy: 0.08571428571428572
time_ms: 20
memory_kb: 80036
final_rank: 15

code_snippet: #include<bits/stdc++.h>
/*m(_ _)m申し訳ございません...*/
#pragma GCC target("avx")
#pragma GCC optimize("O3")
/*m(_ _)m申し訳ございません...*/
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 15
#define NUM 32768

struct Edge{
	Edge(int arg_to_country,int arg_to_city,int arg_cost){
		to_country = arg_to_country;
		to_city = arg_to_city;
		cost = arg_cost;
	}
	int to_country,to_city,cost;
};

struct Edge2{
	Edge2(int arg_to,int arg_cost){
		to = arg_to;
		cost = arg_cost;
	}
	int to,cost;
};

struct Info{
	Info(int arg_num_out,int arg_IN[4],int arg_OUT[4],int arg_cost){
		num_out = arg_num_out;
		for(int i = 0; i < num_out; i++){
			IN[i] = arg_IN[i];
			OUT[i] = arg_OUT[i];
		}
		cost = arg_cost;
	}
	int num_out,IN[4],OUT[4],cost;
};

struct Data{
	void set(int arg_country,int arg_left,int arg_right){
		country = arg_country;
		left = arg_left;
		right = arg_right;
	}
	int country;
	int left,right;
};

struct DEBUG{

	int pre_state,pre_node;
};

int N,K;
int num_city[SIZE],num_outer[SIZE];
int POW[SIZE+1];
int STATE[SIZE];
int ONE[NUM][SIZE];
int DIST[SIZE][SIZE][SIZE][SIZE];
int work_dp[SIZE][NUM][SIZE];
int DP[NUM][SIZE];
int ans;
int num_STATE[SIZE+1];
int table[SIZE+1][NUM];
int LAST[SIZE+1][NUM][SIZE+1],num_LAST[SIZE+1][NUM];
int NEXT[SIZE+1][NUM][SIZE+1][SIZE+1];
int num_NEXT[SIZE+1][NUM][SIZE+1];
int NOT[NUM][SIZE+1],num_NOT[NUM];
bool used[SIZE][4][4][4][4],pair_used[SIZE][4][4];
Data DATA[SIZE];
vector<Edge> same_G[SIZE][SIZE],diff_G[SIZE][SIZE];
vector<Info> info[SIZE];


void calc_2(int index,int work[2],bool is_first){

	if(num_city[index] == 2){ //立ち寄り2回

		int IN[4] = {work[0],work[1],-1,-1};
		int OUT[4] = {work[0],work[1],-1,-1};

		info[index].push_back(Info(2,IN,OUT,0));

	}else{ //first入りsecond出

		if(is_first){

			int first = work[0];
			int second = work[1];

			if(work_dp[first][POW[num_city[index]]-1][second] == BIG_NUM)return;

			int tmp_cost = work_dp[first][POW[num_city[index]]-1][second];

			int IN[4] = {first,-1,-1,-1};
			int OUT[4] = {second,-1,-1,-1};

			info[index].push_back(Info(1,IN,OUT,tmp_cost));

			return;
		}

		do{

			int first = work[0];
			int second = work[1];

			if(work_dp[first][POW[num_city[index]]-1][second] == BIG_NUM)continue;

			int tmp_cost = work_dp[first][POW[num_city[index]]-1][second];

			int IN[4] = {first,-1,-1,-1};
			int OUT[4] = {second,-1,-1,-1};

			info[index].push_back(Info(1,IN,OUT,tmp_cost));

		}while(next_permutation(work,work+2));
	}
}

void calc_3(int index,int work[3],bool is_first){

	if(num_city[index] == 3){ //立ち寄り3回

		int IN[4] = {work[0],work[1],work[2],-1};
		int OUT[4] = {work[0],work[1],work[2],-1};

		info[index].push_back(Info(3,IN,OUT,0));

	}else{ //first立ち寄り,second入りthird出

		if(is_first){

			int first,second,third;

			for(int loop = 0; loop < 3; loop++){
				if(loop == 0){
					first = work[0];
					second = work[1];
					third = work[2];
				}else if(loop == 1){
					first = work[1];
					second = work[0];
					third = work[2];
				}else{
					first = work[2];
					second = work[0];
					third = work[1];
				}

				int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

				if(work_dp[second][to_state][third] < BIG_NUM){

					int IN[4] = {first,second,-1,-1};
					int OUT[4] = {first,third,-1,-1};

					info[index].push_back(Info(2,IN,OUT,work_dp[second][to_state][third]));
				}
			}
			return;
		}

		do{
			int first = work[0];
			int second = work[1];
			int third = work[2];

			int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

			if(work_dp[second][to_state][third] < BIG_NUM){

				int IN[4] = {first,second,-1,-1};
				int OUT[4] = {first,third,-1,-1};

				info[index].push_back(Info(2,IN,OUT,work_dp[second][to_state][third]));
			}

		}while(next_permutation(work,work+3));
	}
}

void calc_4(int index,int work[4],bool is_first){

	if(num_city[index] == 4){ //立ち寄り4回

		int IN[4] = {work[0],work[1],work[2],work[3]};
		int OUT[4] = {work[0],work[1],work[2],work[3]};

		info[index].push_back(Info(4,IN,OUT,0));

	}else{

		if(is_first){

			do{

				int a = work[0];
				int b = work[1];
				int c = work[2];
				int d = work[3];

				//a入りb出-c入d出
				if(a<b&&!used[index][c][d][a][b]){
					used[index][a][b][c][d] = true;

					int to_state = (POW[num_city[index]]-1)-(POW[c]+POW[d]);
					int tmp_cost = BIG_NUM;

					for(int from_state = 1; from_state <= to_state; from_state++){
						if(((from_state & POW[c]) == POW[c]) ||
							((from_state & POW[d]) == POW[d]) ||
							((from_state & POW[a]) != POW[a]) ||
							((from_state & POW[b]) != POW[b]))continue;
						if(work_dp[a][from_state][b] == BIG_NUM)continue;
						if(from_state == POW[a]+POW[b])continue;

						int rest_state = POW[num_city[index]]-1-from_state;
						if(work_dp[c][rest_state][d] == BIG_NUM)continue;
						if(rest_state == POW[c]+POW[d])continue;

						tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
					}

					if(tmp_cost < BIG_NUM){

						int IN[4] = {a,c,-1,-1};
						int OUT[4] = {b,d,-1,-1};

						info[index].push_back(Info(2,IN,OUT,tmp_cost));
					}
				}

				//a,b立ち寄り,c入d出
				if(c<d&&!pair_used[index][c][d]){
					pair_used[index][c][d] = true;

					int to_state = (POW[num_city[index]]-1)-(POW[a]+POW[b]);

					if(work_dp[c][to_state][d] < BIG_NUM){

						int IN[4] = {a,b,c,-1};
						int OUT[4] = {a,b,d,-1};

						info[index].push_back(Info(3,IN,OUT,work_dp[c][to_state][d]));
					}
				}

			}while(next_permutation(work,work+4));

			return;
		}

		do{

			int a = work[0];
			int b = work[1];
			int c = work[2];
			int d = work[3];

			//a入りb出-c入d出
			if(!used[index][c][d][a][b]){
				used[index][a][b][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[c]+POW[d]);
				int tmp_cost = BIG_NUM;

				for(int from_state = 1; from_state <= to_state; from_state++){
					if(((from_state & POW[c]) == POW[c]) ||
						((from_state & POW[d]) == POW[d]) ||
						((from_state & POW[a]) != POW[a]) ||
						((from_state & POW[b]) != POW[b]))continue;
					if(work_dp[a][from_state][b] == BIG_NUM)continue;
					if(from_state == POW[a]+POW[b])continue;

					int rest_state = POW[num_city[index]]-1-from_state;
					if(work_dp[c][rest_state][d] == BIG_NUM)continue;
					if(rest_state == POW[c]+POW[d])continue;

					tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
				}

				if(tmp_cost < BIG_NUM){

					int IN[4] = {a,c,-1,-1};
					int OUT[4] = {b,d,-1,-1};

					info[index].push_back(Info(2,IN,OUT,tmp_cost));
				}
			}

			//a,b立ち寄り,c入d出
			if(!pair_used[index][c][d]){
				pair_used[index][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[a]+POW[b]);

				if(work_dp[c][to_state][d] < BIG_NUM){

					int IN[4] = {a,b,c,-1};
					int OUT[4] = {a,b,d,-1};

					info[index].push_back(Info(3,IN,OUT,work_dp[c][to_state][d]));
				}
			}

		}while(next_permutation(work,work+4));
	}
}

void calc_one(){

	if(num_city[0] == 1){

		printf("0\n");
		return;
	}

	int index = 0;

	for(int state = 0; state < POW[num_city[index]]; state++){
		for(int last = 0; last < num_city[index]; last++){

			ONE[state][last] = BIG_NUM;
		}
	}

	//経路は輪になるので、スタートは0として良いはず
	ONE[POW[0]][0] = 0;

	for(int state = 1; state < POW[num_city[index]]-1; state++){
		for(int last = 0; last < num_city[index]; last++){
			if(ONE[state][last] == BIG_NUM)continue;

			for(int i = 0; i < same_G[index][last].size(); i++){

				int next_node = same_G[index][last][i].to_city;

				if(state & POW[next_node])continue;

				int next_state = state+POW[next_node];
				int next_cost = ONE[state][last]+same_G[index][last][i].cost;

				ONE[next_state][next_node] = min(ONE[next_state][next_node],next_cost);
			}
		}
	}

	int ans = BIG_NUM;
	for(int last = 0; last < num_city[index]; last++){
		if(ONE[POW[num_city[index]]-1][last] == BIG_NUM)continue;

		ans = min(ans,ONE[POW[num_city[index]]-1][last]+DIST[0][last][0][0]);
	}

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}
}
void recursive(int index){

	if(index < N){

		for(int i = 0; i < info[index].size(); i++){

			STATE[index] = i;
			recursive(index+1);
		}
		return;
	}

	//index == N
	int num_DATA = 0;
	int add = 0;

	int work_DIST[SIZE][SIZE];
	for(int i = 0; i < SIZE; i++){
		for(int k = 0; k < SIZE; k++){

			work_DIST[i][k] = BIG_NUM;
		}
	}

	for(int i = 0; i < N; i++){
		add += info[i][STATE[i]].cost;
		for(int k = 0; k < info[i][STATE[i]].num_out; k++){

			DATA[num_DATA++].set(i,info[i][STATE[i]].IN[k],info[i][STATE[i]].OUT[k]);
		}
	}

	if(add >= ans)return;

	for(int i = 0; i < num_DATA; i++){
		for(int k = 1; k < num_DATA; k++){
			if(k == i)continue;

			int from_country = DATA[i].country;
			int from_city = DATA[i].right;

			int to_country = DATA[k].country;
			int to_city = DATA[k].left;

			if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

			work_DIST[i][k] = DIST[from_country][from_city][to_country][to_city];
		}
	}

	for(int state = 0; state < POW[num_DATA]; state++){
		for(int last = 1; last < num_DATA; last++){

			DP[state][last] = BIG_NUM;
		}
	}

	for(int i = 1; i < num_DATA; i++){
		if(work_DIST[0][i] == BIG_NUM)continue;

		DP[POW[0]+POW[i]][i] = work_DIST[0][i];
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		for(int k = 0; k < num_LAST[num_DATA][table[num_DATA][i]]; k++){
			int last = LAST[num_DATA][table[num_DATA][i]][k];
			if(DP[table[num_DATA][i]][last] == BIG_NUM)continue;

			for(int a = 0; a < num_NEXT[num_DATA][table[num_DATA][i]][k]; a++){

				int next = NEXT[num_DATA][table[num_DATA][i]][k][a];
				DP[table[num_DATA][i]+POW[next]][next] = min(DP[table[num_DATA][i]+POW[next]][next],
						DP[table[num_DATA][i]][last]+work_DIST[last][next]);
			}
		}
	}

	int tmp_ans = BIG_NUM;

	for(int last = 1; last < num_DATA; last++){
		if(DP[POW[num_DATA]-1][last] == BIG_NUM)continue;

		int pre_country = DATA[last].country;
		int pre_city = DATA[last].right;

		int next_country = DATA[0].country;
		int next_city = DATA[0].left;

		if(DIST[pre_country][pre_city][next_country][next_city] == BIG_NUM)continue;

		if(tmp_ans > DP[POW[num_DATA]-1][last]+
				DIST[pre_country][pre_city][next_country][next_city]){
			tmp_ans = DP[POW[num_DATA]-1][last]+
					DIST[pre_country][pre_city][next_country][next_city];
		}
	}

	if(tmp_ans < BIG_NUM){

		ans = min(ans,tmp_ans+add);
	}
}

void calc_dp(int index){

	for(int start = 0; start < num_outer[index]; start++){
		for(int state = 0; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){

				work_dp[start][state][last] = BIG_NUM;
			}
		}
	}

	for(int i = 0; i < num_outer[index]; i++){
		work_dp[i][POW[i]][i] = 0;
		for(int state = 1; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){
				if(work_dp[i][state][last] == BIG_NUM)continue;

				for(int next = 0; next < num_city[index]; next++){
					if(state & POW[next])continue;
					if(DIST[index][last][index][next] == BIG_NUM)continue;

					int next_state = state+POW[next];
					int next_cost = work_dp[i][state][last]+DIST[index][last][index][next];

					work_dp[i][next_state][next] = min(work_dp[i][next_state][next],next_cost);
				}
			}
		}
	}
}

void calc_LAST_NEXT(){

	for(int i = 2; i <= 15; i++){
		int maximum = POW[i];
		num_STATE[i] = 0;
		for(int state = 3; state <= maximum-3; state += 2){ //DATA[0]を訪問済の状態のみ列挙

			table[i][num_STATE[i]++] = state;

			num_NOT[state] = 0;
			for(int k = 1; k < i; k++){
				if(state&POW[k])continue;
				NOT[state][num_NOT[state]++] = k;
			}

			num_LAST[i][state] = 0;

			for(int last = 1; last < i; last++){
				if((state&POW[last]) == 0)continue;

				LAST[i][state][num_LAST[i][state]] = last;
				num_NEXT[i][state][num_LAST[i][state]] = 0;

				for(int next = 1; next < i; next++){
					if(next == last)continue;
					if(state&POW[next])continue;

					NEXT[i][state][num_LAST[i][state]][num_NEXT[i][state][num_LAST[i][state]]++] = next;
				}
				num_LAST[i][state]++;
			}
		}
	}
}

int main(){

	POW[0] = 1;
	for(int i = 1; i <= SIZE; i++){

		POW[i] = POW[i-1]*2;
	}

	for(int a = 0; a < SIZE; a++){
		for(int b = 0; b < SIZE; b++){
			for(int c = 0; c < SIZE; c++){
				for(int d = 0; d < SIZE; d++){
					DIST[a][b][c][d] = BIG_NUM;
				}
			}
		}
	}

	for(int i = 0; i < SIZE; i++){
		for(int a = 0; a < 4; a++){
			for(int b = 0; b < 4; b++){
				pair_used[i][a][b] = false;
				for(int c = 0; c < 4; c++){
					for(int d = 0; d < 4; d++){
						used[i][a][b][c][d] = false;
					}
				}
			}
		}
	}

	scanf("%d %d",&N,&K);

	for(int i = 0; i < N; i++){

		scanf("%d",&num_city[i]);
	}
	for(int i = 0; i < N; i++){

		scanf("%d",&num_outer[i]);
	}

	int from_country,from_city,to_country,to_city,cost;

	for(int i = 0; i < K; i++){

		scanf("%d %d %d %d %d",&from_country,&from_city,&to_country,&to_city,&cost);
		from_country--;
		from_city--;
		to_country--;
		to_city--;

		if(from_country == to_country){

			same_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			same_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));

		}else{

			diff_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			diff_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));
		}

		DIST[from_country][from_city][to_country][to_city] = cost;
		DIST[to_country][to_city][from_country][from_city] = cost;
	}

	if(N == 1){

		calc_one();
		return 0;
	}

	calc_LAST_NEXT();

	for(int i = 0; i < N; i++){

		if(num_outer[i] == 1){

			int IN[4] = {0,-1,-1,-1};
			int OUT[4] = {0,-1,-1,-1};

			if(num_city[i] > 1){

				printf("-1\n");
				return 0;

			}else{

				info[i].push_back(Info(1,IN,OUT,0));
			}

		}else if(num_outer[i] == 2){

			calc_dp(i);

			int work[2] = {0,1};

			calc_2(i,work,i==0);

		}else if(num_outer[i] == 3){

			calc_dp(i);

			int work_2[2],work_3[3];

			for(int state = 1; state < POW[3]; state++){
				vector<int> vec;
				for(int loop = 0; loop < 3; loop++){
					if(state&POW[loop]){

						vec.push_back(loop);
					}
				}
				if(vec.size() == 1)continue;

				if(vec.size() == 2){ //国際空港を2つ使う場合

					work_2[0] = vec[0];
					work_2[1] = vec[1];

					calc_2(i,work_2,i==0);

				}else{ //国際空港を3つ使う場合

					work_3[0] = vec[0];
					work_3[1] = vec[1];
					work_3[2] = vec[2];

					calc_3(i,work_3,i==0);
				}
			}

		}else{ //num_outer[i] == 4

			calc_dp(i);

			int work_2[2],work_3[3],work_4[4];

			for(int state = 1; state < POW[4]; state++){
				vector<int> vec;
				for(int loop = 0; loop < 4; loop++){
					if(state&POW[loop]){

						vec.push_back(loop);
					}
				}
				if(vec.size() == 1)continue;

				if(vec.size() == 2){

					work_2[0] = vec[0];
					work_2[1] = vec[1];

					calc_2(i,work_2,i==0);

				}else if(vec.size() == 3){

					work_3[0] = vec[0];
					work_3[1] = vec[1];
					work_3[2] = vec[2];

					calc_3(i,work_3,i==0);

				}else{

					for(int a = 0; a < 4; a++){

						work_4[a] = vec[a];
					}

					calc_4(i,work_4,i==0);
				}
			}
		}
	}

	for(int i = 0; i < N; i++){
		if(info[i].size() == 0){

			printf("-1\n");
			return 0;
		}
	}

	ans = BIG_NUM;
	recursive(0);

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}

	return 0;
}
accuracy: 1
time_ms: 4920
memory_kb: 169484
final_rank: 8

code_snippet: #include<bits/stdc++.h>
#pragma GCC target("avx")
#pragma GCC optimize("O3")
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 15
#define NUM 32768

struct Edge{
	Edge(int arg_to_country,int arg_to_city,int arg_cost){
		to_country = arg_to_country;
		to_city = arg_to_city;
		cost = arg_cost;
	}
	int to_country,to_city,cost;
};

struct Edge2{
	Edge2(int arg_to,int arg_cost){
		to = arg_to;
		cost = arg_cost;
	}
	int to,cost;
};

struct Info{
	Info(int arg_num_out,int arg_IN[4],int arg_OUT[4],int arg_cost){
		num_out = arg_num_out;
		for(int i = 0; i < num_out; i++){
			IN[i] = arg_IN[i];
			OUT[i] = arg_OUT[i];
		}
		cost = arg_cost;
	}
	int num_out,IN[4],OUT[4],cost;
};

struct Data{
	void set(int arg_country,int arg_left,int arg_right){
		country = arg_country;
		left = arg_left;
		right = arg_right;
	}
	int country;
	int left,right;
};

struct DEBUG{

	int pre_state,pre_node;
};

int N,K;
int num_city[SIZE],num_outer[SIZE];
int POW[SIZE+1];
int STATE[SIZE];
int ONE[NUM][SIZE];
int DIST[SIZE][SIZE][SIZE][SIZE];
int work_dp[SIZE][NUM][SIZE];
int DP[NUM][SIZE];
int ans;
int num_STATE[SIZE+1];
int table[SIZE+1][NUM];
int LAST[SIZE+1][NUM][SIZE+1],num_LAST[SIZE+1][NUM];
int NEXT[SIZE+1][NUM][SIZE+1][SIZE+1];
int num_NEXT[SIZE+1][NUM][SIZE+1];
int NOT[NUM][SIZE+1],num_NOT[NUM];
bool used[SIZE][4][4][4][4],pair_used[SIZE][4][4];
Data DATA[SIZE];
vector<Edge> same_G[SIZE][SIZE],diff_G[SIZE][SIZE];
vector<Info> info[SIZE];


void calc_2(int index,int work[2],bool is_first){

	if(num_city[index] == 2){ //立ち寄り2回

		int IN[4] = {work[0],work[1],-1,-1};
		int OUT[4] = {work[0],work[1],-1,-1};

		info[index].push_back(Info(2,IN,OUT,0));

	}else{ //first入りsecond出

		if(is_first){

			int first = work[0];
			int second = work[1];

			if(work_dp[first][POW[num_city[index]]-1][second] == BIG_NUM)return;

			int tmp_cost = work_dp[first][POW[num_city[index]]-1][second];

			int IN[4] = {first,-1,-1,-1};
			int OUT[4] = {second,-1,-1,-1};

			info[index].push_back(Info(1,IN,OUT,tmp_cost));

			return;
		}

		do{

			int first = work[0];
			int second = work[1];

			if(work_dp[first][POW[num_city[index]]-1][second] == BIG_NUM)continue;

			int tmp_cost = work_dp[first][POW[num_city[index]]-1][second];

			int IN[4] = {first,-1,-1,-1};
			int OUT[4] = {second,-1,-1,-1};

			info[index].push_back(Info(1,IN,OUT,tmp_cost));

		}while(next_permutation(work,work+2));
	}
}

void calc_3(int index,int work[3],bool is_first){

	if(num_city[index] == 3){ //立ち寄り3回

		int IN[4] = {work[0],work[1],work[2],-1};
		int OUT[4] = {work[0],work[1],work[2],-1};

		info[index].push_back(Info(3,IN,OUT,0));

	}else{ //first立ち寄り,second入りthird出

		if(is_first){

			int first,second,third;

			for(int loop = 0; loop < 3; loop++){
				if(loop == 0){
					first = work[0];
					second = work[1];
					third = work[2];
				}else if(loop == 1){
					first = work[1];
					second = work[0];
					third = work[2];
				}else{
					first = work[2];
					second = work[0];
					third = work[1];
				}

				int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

				if(work_dp[second][to_state][third] < BIG_NUM){

					int IN[4] = {first,second,-1,-1};
					int OUT[4] = {first,third,-1,-1};

					info[index].push_back(Info(2,IN,OUT,work_dp[second][to_state][third]));
				}
			}
			return;
		}

		do{
			int first = work[0];
			int second = work[1];
			int third = work[2];

			int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

			if(work_dp[second][to_state][third] < BIG_NUM){

				int IN[4] = {first,second,-1,-1};
				int OUT[4] = {first,third,-1,-1};

				info[index].push_back(Info(2,IN,OUT,work_dp[second][to_state][third]));
			}

		}while(next_permutation(work,work+3));
	}
}

void calc_4(int index,int work[4],bool is_first){

	if(num_city[index] == 4){ //立ち寄り4回

		int IN[4] = {work[0],work[1],work[2],work[3]};
		int OUT[4] = {work[0],work[1],work[2],work[3]};

		info[index].push_back(Info(4,IN,OUT,0));

	}else{

		if(is_first){

			do{

				int a = work[0];
				int b = work[1];
				int c = work[2];
				int d = work[3];

				//a入りb出-c入d出
				if(a<b&&!used[index][c][d][a][b]){
					used[index][a][b][c][d] = true;

					int to_state = (POW[num_city[index]]-1)-(POW[c]+POW[d]);
					int tmp_cost = BIG_NUM;

					for(int from_state = 1; from_state <= to_state; from_state++){
						if(((from_state & POW[c]) == POW[c]) ||
							((from_state & POW[d]) == POW[d]) ||
							((from_state & POW[a]) != POW[a]) ||
							((from_state & POW[b]) != POW[b]))continue;
						if(work_dp[a][from_state][b] == BIG_NUM)continue;
						if(from_state == POW[a]+POW[b])continue;

						int rest_state = POW[num_city[index]]-1-from_state;
						if(work_dp[c][rest_state][d] == BIG_NUM)continue;
						if(rest_state == POW[c]+POW[d])continue;

						tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
					}

					if(tmp_cost < BIG_NUM){

						int IN[4] = {a,c,-1,-1};
						int OUT[4] = {b,d,-1,-1};

						info[index].push_back(Info(2,IN,OUT,tmp_cost));
					}
				}

				//a,b立ち寄り,c入d出
				if(c<d&&!pair_used[index][c][d]){
					pair_used[index][c][d] = true;

					int to_state = (POW[num_city[index]]-1)-(POW[a]+POW[b]);

					if(work_dp[c][to_state][d] < BIG_NUM){

						int IN[4] = {a,b,c,-1};
						int OUT[4] = {a,b,d,-1};

						info[index].push_back(Info(3,IN,OUT,work_dp[c][to_state][d]));
					}
				}

			}while(next_permutation(work,work+4));

			return;
		}

		do{

			int a = work[0];
			int b = work[1];
			int c = work[2];
			int d = work[3];

			//a入りb出-c入d出
			if(!used[index][c][d][a][b]){
				used[index][a][b][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[c]+POW[d]);
				int tmp_cost = BIG_NUM;

				for(int from_state = 1; from_state <= to_state; from_state++){
					if(((from_state & POW[c]) == POW[c]) ||
						((from_state & POW[d]) == POW[d]) ||
						((from_state & POW[a]) != POW[a]) ||
						((from_state & POW[b]) != POW[b]))continue;
					if(work_dp[a][from_state][b] == BIG_NUM)continue;
					if(from_state == POW[a]+POW[b])continue;

					int rest_state = POW[num_city[index]]-1-from_state;
					if(work_dp[c][rest_state][d] == BIG_NUM)continue;
					if(rest_state == POW[c]+POW[d])continue;

					tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
				}

				if(tmp_cost < BIG_NUM){

					int IN[4] = {a,c,-1,-1};
					int OUT[4] = {b,d,-1,-1};

					info[index].push_back(Info(2,IN,OUT,tmp_cost));
				}
			}

			//a,b立ち寄り,c入d出
			if(!pair_used[index][c][d]){
				pair_used[index][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[a]+POW[b]);

				if(work_dp[c][to_state][d] < BIG_NUM){

					int IN[4] = {a,b,c,-1};
					int OUT[4] = {a,b,d,-1};

					info[index].push_back(Info(3,IN,OUT,work_dp[c][to_state][d]));
				}
			}

		}while(next_permutation(work,work+4));
	}
}

void calc_one(){

	if(num_city[0] == 1){

		printf("0\n");
		return;
	}

	int index = 0;

	for(int state = 0; state < POW[num_city[index]]; state++){
		for(int last = 0; last < num_city[index]; last++){

			ONE[state][last] = BIG_NUM;
		}
	}

	//経路は輪になるので、スタートは0として良いはず
	ONE[POW[0]][0] = 0;

	for(int state = 1; state < POW[num_city[index]]-1; state++){
		for(int last = 0; last < num_city[index]; last++){
			if(ONE[state][last] == BIG_NUM)continue;

			for(int i = 0; i < same_G[index][last].size(); i++){

				int next_node = same_G[index][last][i].to_city;

				if(state & POW[next_node])continue;

				int next_state = state+POW[next_node];
				int next_cost = ONE[state][last]+same_G[index][last][i].cost;

				ONE[next_state][next_node] = min(ONE[next_state][next_node],next_cost);
			}
		}
	}

	int ans = BIG_NUM;
	for(int last = 0; last < num_city[index]; last++){
		if(ONE[POW[num_city[index]]-1][last] == BIG_NUM)continue;

		ans = min(ans,ONE[POW[num_city[index]]-1][last]+DIST[0][last][0][0]);
	}

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}
}
void recursive(int index){

	if(index < N){

		for(int i = 0; i < info[index].size(); i++){

			STATE[index] = i;
			recursive(index+1);
		}
		return;
	}

	//index == N
	int num_DATA = 0;
	int add = 0;

	int work_DIST[SIZE][SIZE];
	for(int i = 0; i < SIZE; i++){
		for(int k = 0; k < SIZE; k++){

			work_DIST[i][k] = BIG_NUM;
		}
	}

	for(int i = 0; i < N; i++){
		add += info[i][STATE[i]].cost;
		for(int k = 0; k < info[i][STATE[i]].num_out; k++){

			DATA[num_DATA++].set(i,info[i][STATE[i]].IN[k],info[i][STATE[i]].OUT[k]);
		}
	}

	if(add >= ans)return;

	for(int i = 0; i < num_DATA; i++){
		for(int k = 1; k < num_DATA; k++){
			if(k == i)continue;

			int from_country = DATA[i].country;
			int from_city = DATA[i].right;

			int to_country = DATA[k].country;
			int to_city = DATA[k].left;

			if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

			work_DIST[i][k] = DIST[from_country][from_city][to_country][to_city];
		}
	}

	for(int state = 0; state < POW[num_DATA]; state++){
		for(int last = 1; last < num_DATA; last++){

			DP[state][last] = BIG_NUM;
		}
	}

	for(int i = 1; i < num_DATA; i++){
		if(work_DIST[0][i] == BIG_NUM)continue;

		DP[POW[0]+POW[i]][i] = work_DIST[0][i];
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		for(int k = 0; k < num_LAST[num_DATA][table[num_DATA][i]]; k++){
			int last = LAST[num_DATA][table[num_DATA][i]][k];
			if(DP[table[num_DATA][i]][last] == BIG_NUM)continue;

			for(int a = 0; a < num_NEXT[num_DATA][table[num_DATA][i]][k]; a++){

				int next = NEXT[num_DATA][table[num_DATA][i]][k][a];
				DP[table[num_DATA][i]+POW[next]][next] = min(DP[table[num_DATA][i]+POW[next]][next],
						DP[table[num_DATA][i]][last]+work_DIST[last][next]);
			}
		}
	}

	int tmp_ans = BIG_NUM;

	for(int last = 1; last < num_DATA; last++){
		if(DP[POW[num_DATA]-1][last] == BIG_NUM)continue;

		int pre_country = DATA[last].country;
		int pre_city = DATA[last].right;

		int next_country = DATA[0].country;
		int next_city = DATA[0].left;

		if(DIST[pre_country][pre_city][next_country][next_city] == BIG_NUM)continue;

		if(tmp_ans > DP[POW[num_DATA]-1][last]+
				DIST[pre_country][pre_city][next_country][next_city]){
			tmp_ans = DP[POW[num_DATA]-1][last]+
					DIST[pre_country][pre_city][next_country][next_city];
		}
	}

	if(tmp_ans < BIG_NUM){

		ans = min(ans,tmp_ans+add);
	}
}

void calc_dp(int index){

	for(int start = 0; start < num_outer[index]; start++){
		for(int state = 0; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){

				work_dp[start][state][last] = BIG_NUM;
			}
		}
	}

	for(int i = 0; i < num_outer[index]; i++){
		work_dp[i][POW[i]][i] = 0;
		for(int state = 1; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){
				if(work_dp[i][state][last] == BIG_NUM)continue;

				for(int next = 0; next < num_city[index]; next++){
					if(state & POW[next])continue;
					if(DIST[index][last][index][next] == BIG_NUM)continue;

					int next_state = state+POW[next];
					int next_cost = work_dp[i][state][last]+DIST[index][last][index][next];

					work_dp[i][next_state][next] = min(work_dp[i][next_state][next],next_cost);
				}
			}
		}
	}
}

void calc_LAST_NEXT(){

	for(int i = 2; i <= 15; i++){
		int maximum = POW[i];
		num_STATE[i] = 0;
		for(int state = 3; state <= maximum-3; state += 2){ //DATA[0]を訪問済の状態のみ列挙

			table[i][num_STATE[i]++] = state;

			num_NOT[state] = 0;
			for(int k = 1; k < i; k++){
				if(state&POW[k])continue;
				NOT[state][num_NOT[state]++] = k;
			}

			num_LAST[i][state] = 0;

			for(int last = 1; last < i; last++){
				if((state&POW[last]) == 0)continue;

				LAST[i][state][num_LAST[i][state]] = last;
				num_NEXT[i][state][num_LAST[i][state]] = 0;

				for(int next = 1; next < i; next++){
					if(next == last)continue;
					if(state&POW[next])continue;

					NEXT[i][state][num_LAST[i][state]][num_NEXT[i][state][num_LAST[i][state]]++] = next;
				}
				num_LAST[i][state]++;
			}
		}
	}
}

int main(){

	POW[0] = 1;
	for(int i = 1; i <= SIZE; i++){

		POW[i] = POW[i-1]*2;
	}

	for(int a = 0; a < SIZE; a++){
		for(int b = 0; b < SIZE; b++){
			for(int c = 0; c < SIZE; c++){
				for(int d = 0; d < SIZE; d++){
					DIST[a][b][c][d] = BIG_NUM;
				}
			}
		}
	}

	for(int i = 0; i < SIZE; i++){
		for(int a = 0; a < 4; a++){
			for(int b = 0; b < 4; b++){
				pair_used[i][a][b] = false;
				for(int c = 0; c < 4; c++){
					for(int d = 0; d < 4; d++){
						used[i][a][b][c][d] = false;
					}
				}
			}
		}
	}

	scanf("%d %d",&N,&K);

	for(int i = 0; i < N; i++){

		scanf("%d",&num_city[i]);
	}
	for(int i = 0; i < N; i++){

		scanf("%d",&num_outer[i]);
	}

	int from_country,from_city,to_country,to_city,cost;

	for(int i = 0; i < K; i++){

		scanf("%d %d %d %d %d",&from_country,&from_city,&to_country,&to_city,&cost);
		from_country--;
		from_city--;
		to_country--;
		to_city--;

		if(from_country == to_country){

			same_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			same_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));

		}else{

			diff_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			diff_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));
		}

		DIST[from_country][from_city][to_country][to_city] = cost;
		DIST[to_country][to_city][from_country][from_city] = cost;
	}

	if(N == 1){

		calc_one();
		return 0;
	}

	calc_LAST_NEXT();

	for(int i = 0; i < N; i++){

		if(num_outer[i] == 1){

			int IN[4] = {0,-1,-1,-1};
			int OUT[4] = {0,-1,-1,-1};

			if(num_city[i] > 1){

				printf("-1\n");
				return 0;

			}else{

				info[i].push_back(Info(1,IN,OUT,0));
			}

		}else if(num_outer[i] == 2){

			calc_dp(i);

			int work[2] = {0,1};

			calc_2(i,work,i==0);

		}else if(num_outer[i] == 3){

			calc_dp(i);

			int work_2[2],work_3[3];

			for(int state = 1; state < POW[3]; state++){
				vector<int> vec;
				for(int loop = 0; loop < 3; loop++){
					if(state&POW[loop]){

						vec.push_back(loop);
					}
				}
				if(vec.size() == 1)continue;

				if(vec.size() == 2){ //国際空港を2つ使う場合

					work_2[0] = vec[0];
					work_2[1] = vec[1];

					calc_2(i,work_2,i==0);

				}else{ //国際空港を3つ使う場合

					work_3[0] = vec[0];
					work_3[1] = vec[1];
					work_3[2] = vec[2];

					calc_3(i,work_3,i==0);
				}
			}

		}else{ //num_outer[i] == 4

			calc_dp(i);

			int work_2[2],work_3[3],work_4[4];

			for(int state = 1; state < POW[4]; state++){
				vector<int> vec;
				for(int loop = 0; loop < 4; loop++){
					if(state&POW[loop]){

						vec.push_back(loop);
					}
				}
				if(vec.size() == 1)continue;

				if(vec.size() == 2){

					work_2[0] = vec[0];
					work_2[1] = vec[1];

					calc_2(i,work_2,i==0);

				}else if(vec.size() == 3){

					work_3[0] = vec[0];
					work_3[1] = vec[1];
					work_3[2] = vec[2];

					calc_3(i,work_3,i==0);

				}else{

					for(int a = 0; a < 4; a++){

						work_4[a] = vec[a];
					}

					calc_4(i,work_4,i==0);
				}
			}
		}
	}

	for(int i = 0; i < N; i++){
		if(info[i].size() == 0){

			printf("-1\n");
			return 0;
		}
	}

	ans = BIG_NUM;
	recursive(0);

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}

	return 0;
}
accuracy: 1
time_ms: 4970
memory_kb: 169476
final_rank: 9

code_snippet: #include<bits/stdc++.h>
#pragma GCC target("avx")
#pragma GCC optimize("O3")
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 15
#define NUM 32768

struct Edge{
	Edge(int arg_to_country,int arg_to_city,int arg_cost){
		to_country = arg_to_country;
		to_city = arg_to_city;
		cost = arg_cost;
	}
	int to_country,to_city,cost;
};

struct Edge2{
	Edge2(int arg_to,int arg_cost){
		to = arg_to;
		cost = arg_cost;
	}
	int to,cost;
};

struct Info{
	Info(int arg_num_out,int arg_IN[4],int arg_OUT[4],int arg_cost){
		num_out = arg_num_out;
		for(int i = 0; i < num_out; i++){
			IN[i] = arg_IN[i];
			OUT[i] = arg_OUT[i];
		}
		cost = arg_cost;
	}
	int num_out,IN[4],OUT[4],cost;
};

struct Data{
	void set(int arg_country,int arg_left,int arg_right){
		country = arg_country;
		left = arg_left;
		right = arg_right;
	}
	int country;
	int left,right;
};

struct DEBUG{

	int pre_state,pre_node;
};

int N,K;
int num_city[SIZE],num_outer[SIZE];
int POW[SIZE+1];
int STATE[SIZE];
int ONE[NUM][SIZE];
int DIST[SIZE][SIZE][SIZE][SIZE];
int work_dp[SIZE][NUM][SIZE];
int DP[NUM][SIZE];
int ans;
int num_STATE[SIZE+1];
int table[SIZE+1][NUM];
int LAST[SIZE+1][NUM][SIZE+1],num_LAST[SIZE+1][NUM];
int NEXT[SIZE+1][NUM][SIZE+1][SIZE+1];
int num_NEXT[SIZE+1][NUM][SIZE+1];
int NOT[NUM][SIZE+1],num_NOT[NUM];
bool used[SIZE][4][4][4][4],pair_used[SIZE][4][4];
Data DATA[SIZE];
vector<Edge> same_G[SIZE][SIZE],diff_G[SIZE][SIZE];
vector<Info> info[SIZE];


void calc_2(int index,int work[2],bool is_first){

	if(num_city[index] == 2){ //立ち寄り2回

		int IN[4] = {work[0],work[1],-1,-1};
		int OUT[4] = {work[0],work[1],-1,-1};

		info[index].push_back(Info(2,IN,OUT,0));

	}else{ //first入りsecond出

		if(is_first){

			int first = work[0];
			int second = work[1];

			if(work_dp[first][POW[num_city[index]]-1][second] == BIG_NUM)return;

			int tmp_cost = work_dp[first][POW[num_city[index]]-1][second];

			int IN[4] = {first,-1,-1,-1};
			int OUT[4] = {second,-1,-1,-1};

			info[index].push_back(Info(1,IN,OUT,tmp_cost));

			return;
		}

		do{

			int first = work[0];
			int second = work[1];

			if(work_dp[first][POW[num_city[index]]-1][second] == BIG_NUM)continue;

			int tmp_cost = work_dp[first][POW[num_city[index]]-1][second];

			int IN[4] = {first,-1,-1,-1};
			int OUT[4] = {second,-1,-1,-1};

			info[index].push_back(Info(1,IN,OUT,tmp_cost));

		}while(next_permutation(work,work+2));
	}
}

void calc_3(int index,int work[3],bool is_first){

	if(num_city[index] == 3){ //立ち寄り3回

		int IN[4] = {work[0],work[1],work[2],-1};
		int OUT[4] = {work[0],work[1],work[2],-1};

		info[index].push_back(Info(3,IN,OUT,0));

	}else{ //first立ち寄り,second入りthird出

		if(is_first){

			int first,second,third;

			for(int loop = 0; loop < 3; loop++){
				if(loop == 0){
					first = work[0];
					second = work[1];
					third = work[2];
				}else if(loop == 1){
					first = work[1];
					second = work[0];
					third = work[2];
				}else{
					first = work[2];
					second = work[0];
					third = work[1];
				}

				int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

				if(work_dp[second][to_state][third] < BIG_NUM){

					int IN[4] = {first,second,-1,-1};
					int OUT[4] = {first,third,-1,-1};

					info[index].push_back(Info(2,IN,OUT,work_dp[second][to_state][third]));
				}
			}
			return;
		}

		do{
			int first = work[0];
			int second = work[1];
			int third = work[2];

			int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

			if(work_dp[second][to_state][third] < BIG_NUM){

				int IN[4] = {first,second,-1,-1};
				int OUT[4] = {first,third,-1,-1};

				info[index].push_back(Info(2,IN,OUT,work_dp[second][to_state][third]));
			}

		}while(next_permutation(work,work+3));
	}
}

void calc_4(int index,int work[4],bool is_first){

	if(num_city[index] == 4){ //立ち寄り4回

		int IN[4] = {work[0],work[1],work[2],work[3]};
		int OUT[4] = {work[0],work[1],work[2],work[3]};

		info[index].push_back(Info(4,IN,OUT,0));

	}else{

		if(is_first){

			do{

				int a = work[0];
				int b = work[1];
				int c = work[2];
				int d = work[3];

				//a入りb出-c入d出
				if(a<b&&!used[index][c][d][a][b]){
					used[index][a][b][c][d] = true;

					int to_state = (POW[num_city[index]]-1)-(POW[c]+POW[d]);
					int tmp_cost = BIG_NUM;

					for(int from_state = 1; from_state <= to_state; from_state++){
						if(((from_state & POW[c]) == POW[c]) ||
							((from_state & POW[d]) == POW[d]) ||
							((from_state & POW[a]) != POW[a]) ||
							((from_state & POW[b]) != POW[b]))continue;
						if(work_dp[a][from_state][b] == BIG_NUM)continue;
						if(from_state == POW[a]+POW[b])continue;

						int rest_state = POW[num_city[index]]-1-from_state;
						if(work_dp[c][rest_state][d] == BIG_NUM)continue;
						if(rest_state == POW[c]+POW[d])continue;

						tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
					}

					if(tmp_cost < BIG_NUM){

						int IN[4] = {a,c,-1,-1};
						int OUT[4] = {b,d,-1,-1};

						info[index].push_back(Info(2,IN,OUT,tmp_cost));
					}
				}

				//a,b立ち寄り,c入d出
				if(c<d&&!pair_used[index][c][d]){
					pair_used[index][c][d] = true;

					int to_state = (POW[num_city[index]]-1)-(POW[a]+POW[b]);

					if(work_dp[c][to_state][d] < BIG_NUM){

						int IN[4] = {a,b,c,-1};
						int OUT[4] = {a,b,d,-1};

						info[index].push_back(Info(3,IN,OUT,work_dp[c][to_state][d]));
					}
				}

			}while(next_permutation(work,work+4));

			return;
		}

		do{

			int a = work[0];
			int b = work[1];
			int c = work[2];
			int d = work[3];

			//a入りb出-c入d出
			if(!used[index][c][d][a][b]){
				used[index][a][b][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[c]+POW[d]);
				int tmp_cost = BIG_NUM;

				for(int from_state = 1; from_state <= to_state; from_state++){
					if(((from_state & POW[c]) == POW[c]) ||
						((from_state & POW[d]) == POW[d]) ||
						((from_state & POW[a]) != POW[a]) ||
						((from_state & POW[b]) != POW[b]))continue;
					if(work_dp[a][from_state][b] == BIG_NUM)continue;
					if(from_state == POW[a]+POW[b])continue;

					int rest_state = POW[num_city[index]]-1-from_state;
					if(work_dp[c][rest_state][d] == BIG_NUM)continue;
					if(rest_state == POW[c]+POW[d])continue;

					tmp_cost = min(tmp_cost,work_dp[a][from_state][b]+work_dp[c][rest_state][d]);
				}

				if(tmp_cost < BIG_NUM){

					int IN[4] = {a,c,-1,-1};
					int OUT[4] = {b,d,-1,-1};

					info[index].push_back(Info(2,IN,OUT,tmp_cost));
				}
			}

			//a,b立ち寄り,c入d出
			if(!pair_used[index][c][d]){
				pair_used[index][c][d] = true;

				int to_state = (POW[num_city[index]]-1)-(POW[a]+POW[b]);

				if(work_dp[c][to_state][d] < BIG_NUM){

					int IN[4] = {a,b,c,-1};
					int OUT[4] = {a,b,d,-1};

					info[index].push_back(Info(3,IN,OUT,work_dp[c][to_state][d]));
				}
			}

		}while(next_permutation(work,work+4));
	}
}

void calc_one(){

	if(num_city[0] == 1){

		printf("0\n");
		return;
	}

	int index = 0;

	for(int state = 0; state < POW[num_city[index]]; state++){
		for(int last = 0; last < num_city[index]; last++){

			ONE[state][last] = BIG_NUM;
		}
	}

	//経路は輪になるので、スタートは0として良いはず
	ONE[POW[0]][0] = 0;

	for(int state = 1; state < POW[num_city[index]]-1; state++){
		for(int last = 0; last < num_city[index]; last++){
			if(ONE[state][last] == BIG_NUM)continue;

			for(int i = 0; i < same_G[index][last].size(); i++){

				int next_node = same_G[index][last][i].to_city;

				if(state & POW[next_node])continue;

				int next_state = state+POW[next_node];
				int next_cost = ONE[state][last]+same_G[index][last][i].cost;

				ONE[next_state][next_node] = min(ONE[next_state][next_node],next_cost);
			}
		}
	}

	int ans = BIG_NUM;
	for(int last = 0; last < num_city[index]; last++){
		if(ONE[POW[num_city[index]]-1][last] == BIG_NUM)continue;

		ans = min(ans,ONE[POW[num_city[index]]-1][last]+DIST[0][last][0][0]);
	}

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}
}
void recursive(int index){

	if(index < N){

		for(int i = 0; i < info[index].size(); i++){

			STATE[index] = i;
			recursive(index+1);
		}
		return;
	}

	//index == N
	int num_DATA = 0;
	int add = 0;

	int work_DIST[SIZE][SIZE];
	for(int i = 0; i < SIZE; i++){
		for(int k = 0; k < SIZE; k++){

			work_DIST[i][k] = BIG_NUM;
		}
	}

	for(int i = 0; i < N; i++){
		add += info[i][STATE[i]].cost;
		for(int k = 0; k < info[i][STATE[i]].num_out; k++){

			DATA[num_DATA++].set(i,info[i][STATE[i]].IN[k],info[i][STATE[i]].OUT[k]);
		}
	}

	if(add >= ans)return;

	for(int i = 0; i < num_DATA; i++){
		for(int k = 1; k < num_DATA; k++){
			if(k == i)continue;

			int from_country = DATA[i].country;
			int from_city = DATA[i].right;

			int to_country = DATA[k].country;
			int to_city = DATA[k].left;

			if(DIST[from_country][from_city][to_country][to_city] == BIG_NUM)continue;

			work_DIST[i][k] = DIST[from_country][from_city][to_country][to_city];
		}
	}

	for(int state = 0; state < POW[num_DATA]; state++){
		for(int last = 1; last < num_DATA; last++){

			DP[state][last] = BIG_NUM;
		}
	}

	for(int i = 1; i < num_DATA; i++){
		if(work_DIST[0][i] == BIG_NUM)continue;

		DP[POW[0]+POW[i]][i] = work_DIST[0][i];
	}

	for(int i = 0; i < num_STATE[num_DATA]; i++){
		for(int k = 0; k < num_LAST[num_DATA][table[num_DATA][i]]; k++){
			int last = LAST[num_DATA][table[num_DATA][i]][k];
			if(DP[table[num_DATA][i]][last] == BIG_NUM)continue;

			for(int a = 0; a < num_NEXT[num_DATA][table[num_DATA][i]][k]; a++){

				int next = NEXT[num_DATA][table[num_DATA][i]][k][a];
				DP[table[num_DATA][i]+POW[next]][next] = min(DP[table[num_DATA][i]+POW[next]][next],
						DP[table[num_DATA][i]][last]+work_DIST[last][next]);
			}
		}
	}

	int tmp_ans = BIG_NUM;

	for(int last = 1; last < num_DATA; last++){
		if(DP[POW[num_DATA]-1][last] == BIG_NUM)continue;

		int pre_country = DATA[last].country;
		int pre_city = DATA[last].right;

		int next_country = DATA[0].country;
		int next_city = DATA[0].left;

		if(DIST[pre_country][pre_city][next_country][next_city] == BIG_NUM)continue;

		if(tmp_ans > DP[POW[num_DATA]-1][last]+
				DIST[pre_country][pre_city][next_country][next_city]){
			tmp_ans = DP[POW[num_DATA]-1][last]+
					DIST[pre_country][pre_city][next_country][next_city];
		}
	}

	if(tmp_ans < BIG_NUM){

		ans = min(ans,tmp_ans+add);
	}
}

void calc_dp(int index){

	for(int start = 0; start < num_outer[index]; start++){
		for(int state = 0; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){

				work_dp[start][state][last] = BIG_NUM;
			}
		}
	}

	for(int i = 0; i < num_outer[index]; i++){
		work_dp[i][POW[i]][i] = 0;
		for(int state = 1; state < POW[num_city[index]]; state++){
			for(int last = 0; last < num_city[index]; last++){
				if(work_dp[i][state][last] == BIG_NUM)continue;

				for(int next = 0; next < num_city[index]; next++){
					if(state & POW[next])continue;
					if(DIST[index][last][index][next] == BIG_NUM)continue;

					int next_state = state+POW[next];
					int next_cost = work_dp[i][state][last]+DIST[index][last][index][next];

					work_dp[i][next_state][next] = min(work_dp[i][next_state][next],next_cost);
				}
			}
		}
	}
}

void calc_LAST_NEXT(){

	for(int i = 2; i <= 15; i++){
		int maximum = POW[i];
		num_STATE[i] = 0;
		for(int state = 3; state <= maximum-3; state += 2){ //DATA[0]を訪問済の状態のみ列挙

			table[i][num_STATE[i]++] = state;

			num_NOT[state] = 0;
			for(int k = 1; k < i; k++){
				if(state&POW[k])continue;
				NOT[state][num_NOT[state]++] = k;
			}

			num_LAST[i][state] = 0;

			for(int last = 1; last < i; last++){
				if((state&POW[last]) == 0)continue;

				LAST[i][state][num_LAST[i][state]] = last;
				num_NEXT[i][state][num_LAST[i][state]] = 0;

				for(int next = 1; next < i; next++){
					if(next == last)continue;
					if(state&POW[next])continue;

					NEXT[i][state][num_LAST[i][state]][num_NEXT[i][state][num_LAST[i][state]]++] = next;
				}
				num_LAST[i][state]++;
			}
		}
	}
}

int main(){

	POW[0] = 1;
	for(int i = 1; i <= SIZE; i++){

		POW[i] = POW[i-1]*2;
	}

	for(int a = 0; a < SIZE; a++){
		for(int b = 0; b < SIZE; b++){
			for(int c = 0; c < SIZE; c++){
				for(int d = 0; d < SIZE; d++){
					DIST[a][b][c][d] = BIG_NUM;
				}
			}
		}
	}

	for(int i = 0; i < SIZE; i++){
		for(int a = 0; a < 4; a++){
			for(int b = 0; b < 4; b++){
				pair_used[i][a][b] = false;
				for(int c = 0; c < 4; c++){
					for(int d = 0; d < 4; d++){
						used[i][a][b][c][d] = false;
					}
				}
			}
		}
	}

	scanf("%d %d",&N,&K);

	for(int i = 0; i < N; i++){

		scanf("%d",&num_city[i]);
	}
	for(int i = 0; i < N; i++){

		scanf("%d",&num_outer[i]);
	}

	int from_country,from_city,to_country,to_city,cost;

	for(int i = 0; i < K; i++){

		scanf("%d %d %d %d %d",&from_country,&from_city,&to_country,&to_city,&cost);
		from_country--;
		from_city--;
		to_country--;
		to_city--;

		if(from_country == to_country){

			same_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			same_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));

		}else{

			diff_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			diff_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));
		}

		DIST[from_country][from_city][to_country][to_city] = cost;
		DIST[to_country][to_city][from_country][from_city] = cost;
	}

	if(N == 1){

		calc_one();
		return 0;
	}

	calc_LAST_NEXT();

	for(int i = 0; i < N; i++){

		if(num_outer[i] == 1){

			int IN[4] = {0,-1,-1,-1};
			int OUT[4] = {0,-1,-1,-1};

			if(num_city[i] > 1){

				printf("-1\n");
				return 0;

			}else{

				info[i].push_back(Info(1,IN,OUT,0));
			}

		}else if(num_outer[i] == 2){

			calc_dp(i);

			int work[2] = {0,1};

			calc_2(i,work,i==0);

		}else if(num_outer[i] == 3){

			calc_dp(i);

			int work_2[2],work_3[3];

			for(int state = 1; state < POW[3]; state++){
				vector<int> vec;
				for(int loop = 0; loop < 3; loop++){
					if(state&POW[loop]){

						vec.push_back(loop);
					}
				}
				if(vec.size() == 1)continue;

				if(vec.size() == 2){ //国際空港を2つ使う場合

					work_2[0] = vec[0];
					work_2[1] = vec[1];

					calc_2(i,work_2,i==0);

				}else{ //国際空港を3つ使う場合

					work_3[0] = vec[0];
					work_3[1] = vec[1];
					work_3[2] = vec[2];

					calc_3(i,work_3,i==0);
				}
			}

		}else{ //num_outer[i] == 4

			calc_dp(i);

			int work_2[2],work_3[3],work_4[4];

			for(int state = 1; state < POW[4]; state++){
				vector<int> vec;
				for(int loop = 0; loop < 4; loop++){
					if(state&POW[loop]){

						vec.push_back(loop);
					}
				}
				if(vec.size() == 1)continue;

				if(vec.size() == 2){

					work_2[0] = vec[0];
					work_2[1] = vec[1];

					calc_2(i,work_2,i==0);

				}else if(vec.size() == 3){

					work_3[0] = vec[0];
					work_3[1] = vec[1];
					work_3[2] = vec[2];

					calc_3(i,work_3,i==0);

				}else{

					for(int a = 0; a < 4; a++){

						work_4[a] = vec[a];
					}

					calc_4(i,work_4,i==0);
				}
			}
		}
	}

	for(int i = 0; i < N; i++){
		if(info[i].size() == 0){

			printf("-1\n");
			return 0;
		}
		//sort(info[i].begin(),info[i].end());
	}

	ans = BIG_NUM;
	recursive(0);

	//printf("num_dog:%lld\n",num_dog);

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}

	return 0;
}
accuracy: 1
time_ms: 4840
memory_kb: 169452
final_rank: 7

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 15
#define NUM 32768

struct Edge{
	Edge(int arg_to_country,int arg_to_city,int arg_cost){
		to_country = arg_to_country;
		to_city = arg_to_city;
		cost = arg_cost;
	}
	int to_country,to_city,cost;
};

struct Info{
	Info(int arg_num_out,int arg_IN[4],int arg_OUT[4],int arg_cost){
		num_out = arg_num_out;
		for(int i = 0; i < num_out; i++){
			IN[i] = arg_IN[i];
			OUT[i] = arg_OUT[i];
		}
		cost = arg_cost;
	}
	int num_out,IN[4],OUT[4],cost;
};

struct Data{
	void set(int arg_country,int arg_left,int arg_right){
		country = arg_country;
		left = arg_left;
		right = arg_right;
	}
	int country;
	int left,right;
};

struct DEBUG{

	int pre_state,pre_node;
};

int N,K;
int num_city[SIZE],num_outer[SIZE];
int POW[SIZE+1];
int STATE[SIZE];
int ONE[NUM][SIZE];
int DIST[SIZE][SIZE][SIZE][SIZE];
int dp2[NUM][SIZE],dp3[NUM][SIZE],dp4_A[NUM][SIZE],dp4_B[NUM][SIZE];
int DP[NUM][SIZE];
int ans;
bool used[SIZE][4][4][4][4];
Data data[SIZE];
vector<Edge> same_G[SIZE][SIZE],diff_G[SIZE][SIZE];
vector<Info> info[SIZE];
DEBUG debug[NUM][SIZE];


void calc_2(int index,int work[2]){

	if(num_city[index] == 2){ //立ち寄り2回

		int IN[4] = {work[0],work[1],-1,-1};
		int OUT[4] = {work[0],work[1],-1,-1};

		info[index].push_back(Info(2,IN,OUT,0));

	}else{ //first入りsecond出

		do{

			int first = work[0];
			int second = work[1];

			for(int state = 0; state < POW[num_city[index]]; state++){
				for(int last = 0; last < num_city[index]; last++){

					dp2[state][last] = BIG_NUM;
				}
			}

			dp2[POW[first]][first] = 0;

			for(int state = 1; state < POW[num_city[index]]; state++){
				for(int last = 0; last < num_city[index]; last++){
					if(dp2[state][last] == BIG_NUM)continue;

					for(int i = 0; i < same_G[index][last].size(); i++){

						int next_node = same_G[index][last][i].to_city;
						if(state & POW[next_node])continue;

						int next_state = state+POW[next_node];
						int next_cost = dp2[state][last]+same_G[index][last][i].cost;

						dp2[next_state][next_node] = min(dp2[next_state][next_node],next_cost);
					}
				}
			}

			if(dp2[POW[num_city[index]]-1][second] == BIG_NUM)continue;

			int tmp_cost = dp2[POW[num_city[index]]-1][second];

			int IN[4] = {first,-1,-1,-1};
			int OUT[4] = {second,-1,-1,-1};

			info[index].push_back(Info(1,IN,OUT,tmp_cost));

		}while(next_permutation(work,work+2));
	}
}

void calc_3(int index,int work[3]){

	if(num_city[index] == 3){ //立ち寄り3回

		int IN[4] = {work[0],work[1],work[2],-1};
		int OUT[4] = {work[0],work[1],work[2],-1};

		info[index].push_back(Info(3,IN,OUT,0));

	}else{ //first立ち寄り,second入りthird出

		do{
			int first = work[0];
			int second = work[1];
			int third = work[2];

			int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

			for(int state = 0; state <= to_state; state++){
				for(int last = 0; last < num_city[index]; last++){

					dp3[state][last] = BIG_NUM;
				}
			}

			dp3[POW[second]][second] = 0;

			for(int state = 1; state < to_state; state++){
				for(int last = 0; last < num_city[index]; last++){
					if(last == first || dp3[state][last] == BIG_NUM)continue;

					for(int i = 0; i < same_G[index][last].size(); i++){

						int next_node = same_G[index][last][i].to_city;
						if(next_node == first)continue;
						if(state & POW[next_node])continue;

						int next_state = state+POW[next_node];
						int next_cost = dp3[state][last]+same_G[index][last][i].cost;

						dp3[next_state][next_node] = min(dp3[next_state][next_node],next_cost);
					}
				}
			}

			if(dp3[to_state][third] < BIG_NUM){

				int IN[4] = {first,second,-1,-1};
				int OUT[4] = {first,third,-1,-1};

				info[index].push_back(Info(2,IN,OUT,dp3[to_state][third]));
			}

		}while(next_permutation(work,work+3));
	}
}

void calc_4(int index,int work[4]){

	if(num_city[index] == 4){ //立ち寄り4回

		int IN[4] = {work[0],work[1],work[2],work[3]};
		int OUT[4] = {work[0],work[1],work[2],work[3]};

		info[index].push_back(Info(4,IN,OUT,0));

	}else{

		do{

			int a = work[0];
			int b = work[1];
			int c = work[2];
			int d = work[3];

			//a入りb出-c入d出
			if(used[index][a][b][c][d])continue;
			used[index][a][b][c][d] = true;
			used[index][c][d][a][b] = true;

			for(int state = 0; state < POW[num_city[index]]; state++){
				for(int last = 0; last < num_city[index]; last++){
					dp4_A[state][last] = BIG_NUM;
					dp4_B[state][last] = BIG_NUM;
				}
			}

			dp4_A[POW[a]][a] = 0;
			for(int state = 1; state < POW[num_city[index]]-1; state++){
				for(int last = 0; last < num_city[index]; last++){
					if(last == c || last == d || dp4_A[state][last] == BIG_NUM)continue;

					for(int i = 0; i < same_G[index][last].size(); i++){

						int next_node = same_G[index][last][i].to_city;
						if(next_node == c || next_node == d)continue;
						if(state & POW[next_node])continue;

						int next_state = state+POW[next_node];
						int next_cost = dp4_A[state][last]+same_G[index][last][i].cost;

						dp4_A[next_state][next_node] = min(dp4_A[next_state][next_node],next_cost);
					}
				}
			}

			dp4_B[POW[c]][c] = 0;
			for(int state = 1; state < POW[num_city[index]]-1; state++){
				for(int last = 0; last < num_city[index]; last++){
					if(last == a || last == b || dp4_B[state][last] == BIG_NUM)continue;

					for(int i = 0; i < same_G[index][last].size(); i++){

						int next_node = same_G[index][last][i].to_city;
						if(next_node == a || next_node == b)continue;
						if(state & POW[next_node])continue;

						int next_state = state+POW[next_node];
						int next_cost = dp4_B[state][last]+same_G[index][last][i].cost;

						dp4_B[next_state][next_node] = min(dp4_B[next_state][next_node],next_cost);
					}
				}
			}

			int tmp_cost = BIG_NUM;
			for(int from_state = 1; from_state < POW[num_city[index]]; from_state++){
				if(((from_state & POW[c]) == POW[c]) ||
					((from_state & POW[d]) == POW[d]) ||
					((from_state & POW[a]) != POW[a]) ||
					((from_state & POW[b]) != POW[b]))continue;
				if(dp4_A[from_state][b] == BIG_NUM)continue;

				int rest_state = POW[num_city[index]]-1-from_state;
				if(dp4_B[rest_state][d] == BIG_NUM)continue;

				tmp_cost = min(tmp_cost,dp4_A[from_state][b]+dp4_B[rest_state][d]);
			}

			if(tmp_cost < BIG_NUM){

				int IN[4] = {a,c,-1,-1};
				int OUT[4] = {b,d,-1,-1};

				info[index].push_back(Info(2,IN,OUT,tmp_cost));
			}

			//a,b立ち寄り,c入d出
			for(int state = 0; state < POW[num_city[index]]; state++){
				for(int last = 0; last < num_city[index]; last++){
					dp4_A[state][last] = BIG_NUM;
				}
			}

			dp4_A[POW[c]][c] = 0;
			for(int state = 1; state < POW[num_city[index]]-1; state++){
				for(int last = 0; last < num_city[index]; last++){
					if(last == a || last == b || dp4_A[state][last] == BIG_NUM)continue;

					for(int i = 0; i < same_G[index][last].size(); i++){

						int next_node = same_G[index][last][i].to_city;
						if(next_node == a || next_node == b)continue;
						if(state & POW[next_node])continue;

						int next_state = state+POW[next_node];
						int next_cost = dp4_A[state][last]+same_G[index][last][i].cost;

						dp4_A[next_state][next_node] = min(dp4_A[next_state][next_node],next_cost);
					}
				}
			}

			int to_state = POW[num_city[index]]-1-(POW[a]+POW[b]);

			if(dp4_A[to_state][d] < BIG_NUM){

				int IN[4] = {a,b,c,-1};
				int OUT[4] = {a,b,d,-1};

				info[index].push_back(Info(3,IN,OUT,dp4_A[to_state][d]));
			}

		}while(next_permutation(work,work+4));
	}
}

void calc_one(){

	if(num_city[0] == 1){

		printf("0\n");
		return;
	}

	int index = 0;

	for(int state = 0; state < POW[num_city[index]]; state++){
		for(int last = 0; last < num_city[index]; last++){

			ONE[state][last] = BIG_NUM;
		}
	}

	//経路は輪になるので、スタートは0として良いはず
	ONE[POW[0]][0] = 0;

	for(int state = 1; state < POW[num_city[index]]-1; state++){
		for(int last = 0; last < num_city[index]; last++){
			if(ONE[state][last] == BIG_NUM)continue;

			for(int i = 0; i < same_G[index][last].size(); i++){

				int next_node = same_G[index][last][i].to_city;

				if(state & POW[next_node])continue;

				int next_state = state+POW[next_node];
				int next_cost = ONE[state][last]+same_G[index][last][i].cost;

				ONE[next_state][next_node] = min(ONE[next_state][next_node],next_cost);
			}
		}
	}

	int ans = BIG_NUM;
	for(int last = 0; last < num_city[index]; last++){
		if(ONE[POW[num_city[index]]-1][last] == BIG_NUM)continue;

		ans = min(ans,ONE[POW[num_city[index]]-1][last]+DIST[0][last][0][0]);
	}

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}
}

void recursive(int index){

	if(index < N){

		for(int i = 0; i < info[index].size(); i++){

			STATE[index] = i;
			recursive(index+1);
		}
		return;
	}

	//index == N
	int num_data = 0;
	int add = 0;

	for(int i = 0; i < N; i++){
		add += info[i][STATE[i]].cost;
		for(int k = 0; k < info[i][STATE[i]].num_out; k++){

			data[num_data++].set(i,info[i][STATE[i]].IN[k],info[i][STATE[i]].OUT[k]);
		}
	}

	for(int state = 0; state < POW[num_data]; state++){
		for(int last = 0; last < num_data; last++){

			DP[state][last] = BIG_NUM;
			debug[state][last].pre_node = -1;
		}
	}

	DP[POW[0]][0] = 0;

	for(int state = 1; state < POW[num_data]-1; state++){
		for(int last = 0; last < num_data; last++){
			if(DP[state][last] == BIG_NUM)continue;

			for(int next = 0; next < num_data; next++){
				if(state & POW[next])continue;

				int pre_country = data[last].country;
				int pre_city = data[last].right;

				int next_country = data[next].country;
				int next_city = data[next].left;

				if(DIST[pre_country][pre_city][next_country][next_city] == BIG_NUM)continue;

				int next_state = state+POW[next];
				int next_cost = DP[state][last]+DIST[pre_country][pre_city][next_country][next_city];

				if(DP[next_state][next] > next_cost){
					DP[next_state][next] = next_cost;
					debug[next_state][next].pre_state = state;
					debug[next_state][next].pre_node = last;
				}
			}
		}
	}

	int tmp_ans = BIG_NUM;
	int LAST = -1;

	for(int last = 0; last < num_data; last++){
		if(DP[POW[num_data]-1][last] == BIG_NUM)continue;

		int pre_country = data[last].country;
		int pre_city = data[last].right;

		int next_country = data[0].country;
		int next_city = data[0].left;

		if(DIST[pre_country][pre_city][next_country][next_city] == BIG_NUM)continue;

		if(tmp_ans > DP[POW[num_data]-1][last]+
				DIST[pre_country][pre_city][next_country][next_city]){
			tmp_ans = DP[POW[num_data]-1][last]+
					DIST[pre_country][pre_city][next_country][next_city];
			LAST = last;
		}
	}

	if(tmp_ans < BIG_NUM){

		ans = min(ans,tmp_ans+add);
	}
}

int main(){

	POW[0] = 1;
	for(int i = 1; i <= SIZE; i++){

		POW[i] = POW[i-1]*2;
	}

	for(int a = 0; a < SIZE; a++){
		for(int b = 0; b < SIZE; b++){
			for(int c = 0; c < SIZE; c++){
				for(int d = 0; d < SIZE; d++){
					DIST[a][b][c][d] = BIG_NUM;
				}
			}
		}
	}

	for(int i = 0; i < SIZE; i++){
		for(int a = 0; a < 4; a++){
			for(int b = 0; b < 4; b++){
				for(int c = 0; c < 4; c++){
					for(int d = 0; d < 4; d++){
						used[i][a][b][c][d] = false;
					}
				}
			}
		}
	}

	scanf("%d %d",&N,&K);

	for(int i = 0; i < N; i++){

		scanf("%d",&num_city[i]);
	}
	for(int i = 0; i < N; i++){

		scanf("%d",&num_outer[i]);
	}

	int from_country,from_city,to_country,to_city,cost;

	for(int i = 0; i < K; i++){

		scanf("%d %d %d %d %d",&from_country,&from_city,&to_country,&to_city,&cost);
		from_country--;
		from_city--;
		to_country--;
		to_city--;

		if(from_country == to_country){

			same_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			same_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));

		}else{

			diff_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			diff_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));
		}

		DIST[from_country][from_city][to_country][to_city] = cost;
		DIST[to_country][to_city][from_country][from_city] = cost;
	}

	if(N == 1){

		calc_one();
		return 0;
	}

	for(int i = 0; i < N; i++){

		if(num_outer[i] == 1){

			int IN[4] = {0,-1,-1,-1};
			int OUT[4] = {0,-1,-1,-1};

			if(num_city[i] > 1){

				printf("-1\n");
				return 0;

			}else{

				info[i].push_back(Info(1,IN,OUT,0));
			}

		}else if(num_outer[i] == 2){

			int work[2] = {0,1};

			calc_2(i,work);

		}else if(num_outer[i] == 3){

			int work_2[2],work_3[3];

			for(int state = 1; state < POW[3]; state++){
				vector<int> vec;
				for(int loop = 0; loop < 3; loop++){
					if(state&POW[loop]){

						vec.push_back(loop);
					}
				}
				if(vec.size() == 1)continue;

				if(vec.size() == 2){ //国際空港を2つ使う場合

					work_2[0] = vec[0];
					work_2[1] = vec[1];

					calc_2(i,work_2);

				}else{ //国際空港を3つ使う場合

					work_3[0] = vec[0];
					work_3[1] = vec[1];
					work_3[2] = vec[2];

					calc_3(i,work_3);
				}
			}

		}else{ //num_outer[i] == 4

			int work_2[2],work_3[3],work_4[4];

			for(int state = 1; state < POW[4]; state++){
				vector<int> vec;
				for(int loop = 0; loop < 4; loop++){
					if(state&POW[loop]){

						vec.push_back(loop);
					}
				}
				if(vec.size() == 1)continue;

				if(vec.size() == 2){

					work_2[0] = vec[0];
					work_2[1] = vec[1];

					calc_2(i,work_2);

				}else if(vec.size() == 3){

					work_3[0] = vec[0];
					work_3[1] = vec[1];
					work_3[2] = vec[2];

					calc_3(i,work_3);

				}else{

					for(int a = 0; a < 4; a++){

						work_4[a] = vec[a];
					}

					calc_4(i,work_4);
				}
			}
		}
	}

	for(int i = 0; i < N; i++){
		if(info[i].size() == 0){

			printf("-1\n");
			return 0;
		}
	}

	/*for(int i = 0; i < N; i++){

		printf("\n\ni:%d\n",i);
		for(int k = 0; k < info[i].size(); k++){
			printf("k:%d num:%d cost:%d\n",k,info[i][k].num_out,info[i][k].cost);
			for(int a = 0; a < info[i][k].num_out; a++){

				printf("%d入り%d出\n",info[i][k].IN[a],info[i][k].OUT[a]);
			}
		}
	}

	return 0;*/


	ans = BIG_NUM;
	recursive(0);

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}

	return 0;
}
accuracy: 0.7428571428571429
time_ms: 1220
memory_kb: 11212
final_rank: 11

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 1000000000000000000
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 15
#define NUM 32768

struct Edge{
	Edge(int arg_to_country,int arg_to_city,int arg_cost){
		to_country = arg_to_country;
		to_city = arg_to_city;
		cost = arg_cost;
	}
	int to_country,to_city,cost;
};

struct Info{
	Info(int arg_num_out,int arg_IN[4],int arg_OUT[4],int arg_cost){
		num_out = arg_num_out;
		for(int i = 0; i < num_out; i++){
			IN[i] = arg_IN[i];
			OUT[i] = arg_OUT[i];
		}
		cost = arg_cost;
	}
	int num_out,IN[4],OUT[4],cost;
};

struct Data{
	void set(int arg_country,int arg_left,int arg_right){
		country = arg_country;
		left = arg_left;
		right = arg_right;
	}
	int country;
	int left,right;
};

struct DEBUG{

	int pre_state,pre_node;
};

int N,K;
int num_city[SIZE],num_outer[SIZE];
int POW[SIZE+1];
int STATE[SIZE];
int ONE[NUM][SIZE];
int DIST[SIZE][SIZE][SIZE][SIZE];
int dp2[NUM][SIZE],dp3[NUM][SIZE],dp4_A[NUM][SIZE],dp4_B[NUM][SIZE];
int DP[NUM][SIZE];
int ans;
bool used[SIZE][4][4][4][4];
Data data[SIZE];
vector<Edge> same_G[SIZE][SIZE],diff_G[SIZE][SIZE];
vector<Info> info[SIZE];
DEBUG debug[NUM][SIZE];


void calc_2(int index,int work[2]){

	if(num_city[index] == 2){ //立ち寄り2回

		int IN[4] = {work[0],work[1],-1,-1};
		int OUT[4] = {work[0],work[1],-1,-1};

		info[index].push_back(Info(2,IN,OUT,0));

	}else{ //first入りsecond出

		do{

			int first = work[0];
			int second = work[1];

			for(int state = 0; state < POW[num_city[index]]; state++){
				for(int last = 0; last < num_city[index]; last++){

					dp2[state][last] = BIG_NUM;
				}
			}

			dp2[POW[first]][first] = 0;

			for(int state = 1; state < POW[num_city[index]]; state++){
				for(int last = 0; last < num_city[index]; last++){
					if(dp2[state][last] == BIG_NUM)continue;

					for(int i = 0; i < same_G[index][last].size(); i++){

						int next_node = same_G[index][last][i].to_city;
						if(state & POW[next_node])continue;

						int next_state = state+POW[next_node];
						int next_cost = dp2[state][last]+same_G[index][last][i].cost;

						dp2[next_state][next_node] = min(dp2[next_state][next_node],next_cost);
					}
				}
			}

			if(dp2[POW[num_city[index]]-1][second] == BIG_NUM)continue;

			int tmp_cost = dp2[POW[num_city[index]]-1][second];

			int IN[4] = {first,-1,-1,-1};
			int OUT[4] = {second,-1,-1,-1};

			info[index].push_back(Info(1,IN,OUT,tmp_cost));

		}while(next_permutation(work,work+2));
	}
}

void calc_3(int index,int work[3]){

	if(num_city[index] == 3){ //立ち寄り3回

		int IN[4] = {work[0],work[1],work[2],-1};
		int OUT[4] = {work[0],work[1],work[2],-1};

		info[index].push_back(Info(3,IN,OUT,0));

	}else{ //first立ち寄り,second入りthird出

		do{
			int first = work[0];
			int second = work[1];
			int third = work[2];

			int to_state = (POW[num_city[index]]-1)-POW[first]; //firstを除いてTSP

			for(int state = 0; state <= to_state; state++){
				for(int last = 0; last < num_city[index]; last++){

					dp3[state][last] = BIG_NUM;
				}
			}

			dp3[POW[second]][second] = 0;

			for(int state = 1; state < to_state; state++){
				for(int last = 0; last < num_city[index]; last++){
					if(last == first || dp3[state][last] == BIG_NUM)continue;

					for(int i = 0; i < same_G[index][last].size(); i++){

						int next_node = same_G[index][last][i].to_city;
						if(next_node == first)continue;
						if(state & POW[next_node])continue;

						int next_state = state+POW[next_node];
						int next_cost = dp3[state][last]+same_G[index][last][i].cost;

						dp3[next_state][next_node] = min(dp3[next_state][next_node],next_cost);
					}
				}
			}

			if(dp3[to_state][third] < BIG_NUM){

				int IN[4] = {first,second,-1,-1};
				int OUT[4] = {first,third,-1,-1};

				info[index].push_back(Info(2,IN,OUT,dp3[to_state][third]));
			}

		}while(next_permutation(work,work+3));
	}
}

void calc_4(int index,int work[4]){

	if(num_city[index] == 4){ //立ち寄り4回

		int IN[4] = {work[0],work[1],work[2],work[3]};
		int OUT[4] = {work[0],work[1],work[2],work[3]};

		info[index].push_back(Info(4,IN,OUT,0));

	}else{

		do{

			int a = work[0];
			int b = work[1];
			int c = work[2];
			int d = work[3];

			//a入りb出-c入d出
			if(used[index][a][b][c][d])continue;
			used[index][a][b][c][d] = true;
			used[index][c][d][a][b] = true;

			for(int state = 0; state < POW[num_city[index]]; state++){
				for(int last = 0; last < num_city[index]; last++){
					dp4_A[state][last] = BIG_NUM;
					dp4_B[state][last] = BIG_NUM;
				}
			}

			dp4_A[POW[a]][a] = 0;
			for(int state = 1; state < POW[num_city[index]]-1; state++){
				for(int last = 0; last < num_city[index]; last++){
					if(last == c || last == d || dp4_A[state][last] == BIG_NUM)continue;

					for(int i = 0; i < same_G[index][last].size(); i++){

						int next_node = same_G[index][last][i].to_city;
						if(next_node == c || next_node == d)continue;
						if(state & POW[next_node])continue;

						int next_state = state+POW[next_node];
						int next_cost = dp4_A[state][last]+same_G[index][last][i].cost;

						dp4_A[next_state][next_node] = min(dp4_A[next_state][next_node],next_cost);
					}
				}
			}

			dp4_B[POW[c]][c] = 0;
			for(int state = 1; state < POW[num_city[index]]-1; state++){
				for(int last = 0; last < num_city[index]; last++){
					if(last == a || last == b || dp4_B[state][last] == BIG_NUM)continue;

					for(int i = 0; i < same_G[index][last].size(); i++){

						int next_node = same_G[index][last][i].to_city;
						if(next_node == a || next_node == b)continue;
						if(state & POW[next_node])continue;

						int next_state = state+POW[next_node];
						int next_cost = dp4_B[state][last]+same_G[index][last][i].cost;

						dp4_B[next_state][next_node] = min(dp4_B[next_state][next_node],next_cost);
					}
				}
			}

			int tmp_cost = BIG_NUM;
			for(int from_state = 1; from_state < POW[num_city[index]]; from_state++){
				if(((from_state & POW[c]) == POW[c]) ||
					((from_state & POW[d]) == POW[d]) ||
					((from_state & POW[a]) != POW[a]) ||
					((from_state & POW[b]) != POW[b]))continue;
				if(dp4_A[from_state][b] == BIG_NUM)continue;

				int rest_state = POW[num_city[index]]-1-from_state;
				if(dp4_B[rest_state][d] == BIG_NUM)continue;

				tmp_cost = min(tmp_cost,dp4_A[from_state][b]+dp4_B[rest_state][d]);
			}

			if(tmp_cost < BIG_NUM){

				int IN[4] = {a,c,-1,-1};
				int OUT[4] = {b,d,-1,-1};

				info[index].push_back(Info(2,IN,OUT,tmp_cost));
			}

			//a,b立ち寄り,c入d出
			for(int state = 0; state < POW[num_city[index]]; state++){
				for(int last = 0; last < num_city[index]; last++){
					dp4_A[state][last] = BIG_NUM;
				}
			}

			dp4_A[POW[c]][c] = 0;
			for(int state = 1; state < POW[num_city[index]]-1; state++){
				for(int last = 0; last < num_city[index]; last++){
					if(last == a || last == b || dp4_A[state][last] == BIG_NUM)continue;

					for(int i = 0; i < same_G[index][last].size(); i++){

						int next_node = same_G[index][last][i].to_city;
						if(next_node == a || next_node == b)continue;
						if(state & POW[next_node])continue;

						int next_state = state+POW[next_node];
						int next_cost = dp4_A[state][last]+same_G[index][last][i].cost;

						dp4_A[next_state][next_node] = min(dp4_A[next_state][next_node],next_cost);
					}
				}
			}

			int to_state = POW[num_city[index]]-1-(POW[a]+POW[b]);

			if(dp4_A[to_state][d] < BIG_NUM){

				int IN[4] = {a,b,c,-1};
				int OUT[4] = {a,b,d,-1};

				info[index].push_back(Info(3,IN,OUT,dp4_A[to_state][d]));
			}

		}while(next_permutation(work,work+4));
	}
}

void calc_one(){

	if(num_city[0] == 1){

		printf("0\n");
		return;
	}

	int index = 0;

	for(int state = 0; state < POW[num_city[index]]; state++){
		for(int last = 0; last < num_city[index]; last++){

			ONE[state][last] = BIG_NUM;
		}
	}

	//経路は輪になるので、スタートは0として良いはず
	ONE[POW[0]][0] = 0;

	for(int state = 1; state < POW[num_city[index]]-1; state++){
		for(int last = 0; last < num_city[index]; last++){
			if(ONE[state][last] == BIG_NUM)continue;

			for(int i = 0; i < same_G[index][last].size(); i++){

				int next_node = same_G[index][last][i].to_city;

				if(state & POW[next_node])continue;

				int next_state = state+POW[state];
				int next_cost = ONE[state][last]+same_G[index][last][i].cost;


				ONE[next_state][next_node] = min(ONE[next_state][next_node],next_cost);
			}
		}
	}

	int ans = BIG_NUM;
	for(int last = 0; last < num_city[index]; last++){
		if(ONE[POW[num_city[index]]-1][last] == BIG_NUM)continue;

		ans = min(ans,ONE[POW[num_city[index]]-1][last]+DIST[0][last][0][0]);
	}

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}
}

void recursive(int index){

	if(index < N){

		for(int i = 0; i < info[index].size(); i++){

			STATE[index] = i;
			recursive(index+1);
		}
		return;
	}

	//index == N
	int num_data = 0;
	int add = 0;

	for(int i = 0; i < N; i++){
		add += info[i][STATE[i]].cost;
		for(int k = 0; k < info[i][STATE[i]].num_out; k++){

			data[num_data++].set(i,info[i][STATE[i]].IN[k],info[i][STATE[i]].OUT[k]);
		}
	}

	for(int state = 0; state < POW[num_data]; state++){
		for(int last = 0; last < num_data; last++){

			DP[state][last] = BIG_NUM;
			debug[state][last].pre_node = -1;
		}
	}

	DP[POW[0]][0] = 0;

	for(int state = 1; state < POW[num_data]-1; state++){
		for(int last = 0; last < num_data; last++){
			if(DP[state][last] == BIG_NUM)continue;

			for(int next = 0; next < num_data; next++){
				if(state & POW[next])continue;

				int pre_country = data[last].country;
				int pre_city = data[last].right;

				int next_country = data[next].country;
				int next_city = data[next].left;

				if(DIST[pre_country][pre_city][next_country][next_city] == BIG_NUM)continue;

				int next_state = state+POW[next];
				int next_cost = DP[state][last]+DIST[pre_country][pre_city][next_country][next_city];

				if(DP[next_state][next] > next_cost){
					DP[next_state][next] = next_cost;
					debug[next_state][next].pre_state = state;
					debug[next_state][next].pre_node = last;
				}
			}
		}
	}

	int tmp_ans = BIG_NUM;
	int LAST = -1;

	for(int last = 0; last < num_data; last++){
		if(DP[POW[num_data]-1][last] == BIG_NUM)continue;

		int pre_country = data[last].country;
		int pre_city = data[last].right;

		int next_country = data[0].country;
		int next_city = data[0].left;

		if(DIST[pre_country][pre_city][next_country][next_city] == BIG_NUM)continue;

		if(tmp_ans > DP[POW[num_data]-1][last]+
				DIST[pre_country][pre_city][next_country][next_city]){
			tmp_ans = DP[POW[num_data]-1][last]+
					DIST[pre_country][pre_city][next_country][next_city];
			LAST = last;
		}
	}

	if(tmp_ans < BIG_NUM){

		ans = min(ans,tmp_ans+add);
	}
}

int main(){

	POW[0] = 1;
	for(int i = 1; i <= SIZE; i++){

		POW[i] = POW[i-1]*2;
	}

	for(int a = 0; a < SIZE; a++){
		for(int b = 0; b < SIZE; b++){
			for(int c = 0; c < SIZE; c++){
				for(int d = 0; d < SIZE; d++){
					DIST[a][b][c][d] = BIG_NUM;
				}
			}
		}
	}

	for(int i = 0; i < SIZE; i++){
		for(int a = 0; a < 4; a++){
			for(int b = 0; b < 4; b++){
				for(int c = 0; c < 4; c++){
					for(int d = 0; d < 4; d++){
						used[i][a][b][c][d] = false;
					}
				}
			}
		}
	}

	scanf("%d %d",&N,&K);

	for(int i = 0; i < N; i++){

		scanf("%d",&num_city[i]);
	}
	for(int i = 0; i < N; i++){

		scanf("%d",&num_outer[i]);
	}

	int from_country,from_city,to_country,to_city,cost;

	for(int i = 0; i < K; i++){

		scanf("%d %d %d %d %d",&from_country,&from_city,&to_country,&to_city,&cost);
		from_country--;
		from_city--;
		to_country--;
		to_city--;

		if(from_country == to_country){

			same_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			same_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));

		}else{

			diff_G[from_country][from_city].push_back(Edge(to_country,to_city,cost));
			diff_G[to_country][to_city].push_back(Edge(from_country,from_city,cost));
		}

		DIST[from_country][from_city][to_country][to_city] = cost;
		DIST[to_country][to_city][from_country][from_city] = cost;
	}

	if(N == 1){

		calc_one();
		return 0;
	}
/*
	debug_TSP();
	return 0;*/

	for(int i = 0; i < N; i++){

		if(num_outer[i] == 1){

			int IN[4] = {0,-1,-1,-1};
			int OUT[4] = {0,-1,-1,-1};

			if(num_city[i] > 1){

				printf("-1\n");
				return 0;

			}else{

				info[i].push_back(Info(1,IN,OUT,0));
			}

		}else if(num_outer[i] == 2){

			int work[2] = {0,1};

			calc_2(i,work);

		}else if(num_outer[i] == 3){

			int work_2[2],work_3[3];

			for(int state = 1; state < POW[3]; state++){
				vector<int> vec;
				for(int loop = 0; loop < 3; loop++){
					if(state&POW[loop]){

						vec.push_back(loop);
					}
				}
				if(vec.size() == 1)continue;

				if(vec.size() == 2){ //国際空港を2つ使う場合

					work_2[0] = vec[0];
					work_2[1] = vec[1];

					calc_2(i,work_2);

				}else{ //国際空港を3つ使う場合

					work_3[0] = vec[0];
					work_3[1] = vec[1];
					work_3[2] = vec[2];

					calc_3(i,work_3);
				}
			}

		}else{ //num_outer[i] == 4

			int work_2[2],work_3[3],work_4[4];

			for(int state = 1; state < POW[4]; state++){
				vector<int> vec;
				for(int loop = 0; loop < 4; loop++){
					if(state&POW[loop]){

						vec.push_back(loop);
					}
				}
				if(vec.size() == 1)continue;

				if(vec.size() == 2){

					work_2[0] = vec[0];
					work_2[1] = vec[1];

					calc_2(i,work_2);

				}else if(vec.size() == 3){

					work_3[0] = vec[0];
					work_3[1] = vec[1];
					work_3[2] = vec[2];

					calc_3(i,work_3);

				}else{

					for(int a = 0; a < 4; a++){

						work_4[a] = vec[a];
					}

					calc_4(i,work_4);
				}
			}
		}
	}

	for(int i = 0; i < N; i++){
		if(info[i].size() == 0){

			printf("-1\n");
			return 0;
		}
	}

	/*for(int i = 0; i < N; i++){

		printf("\n\ni:%d\n",i);
		for(int k = 0; k < info[i].size(); k++){
			printf("k:%d num:%d cost:%d\n",k,info[i][k].num_out,info[i][k].cost);
			for(int a = 0; a < info[i][k].num_out; a++){

				printf("%d入り%d出\n",info[i][k].IN[a],info[i][k].OUT[a]);
			}
		}
	}

	return 0;*/


	ans = BIG_NUM;
	recursive(0);

	if(ans == BIG_NUM){

		printf("-1\n");
	}else{

		printf("%d\n",ans);
	}

	return 0;
}
accuracy: 0.2857142857142857
time_ms: 290
memory_kb: 9232
final_rank: 13