Problem:
Problem B: Make Purse Light

Mr. Bill は店で買い物をしている。 彼の財布にはいくらかの硬貨（10 円玉、50 円玉、100 円玉、500 円玉）が入っているが、彼は今この小銭をできるだけ消費しようとしている。 つまり、適切な枚数の硬貨によって品物の代金を払うことで、釣り銭を受け取った後における硬貨の合計枚数を最小にしようとしている。

幸いなことに、この店の店員はとても律儀かつ親切であるため、釣り銭は常に最適な方法で渡される。 したがって、例えば 1 枚の 500 円玉の代わりに 5 枚の 100 円玉が渡されるようなことはない。 また、例えば 10 円玉を 5 枚出して、50 円玉を釣り銭として受け取ることもできる。 ただし、出した硬貨と同じ種類の硬貨が釣り銭として戻ってくるような払いかたをしてはいけない。 例えば、10 円玉を支払いの際に出したにも関わらず、別の 10 円玉が釣り銭として戻されるようでは、完全に意味のないやりとりが発生してしまうからである。

ところが Mr. Bill は計算が苦手なため、実際に何枚の硬貨を使用すればよいかを彼自身で求めることができなかった。 そこで、彼はあなたに助けを求めてきた。 あなたの仕事は、彼の財布の中にある硬貨の枚数と支払い代金をもとに、使用すべき硬貨の種類と枚数を求めるプログラムを書くことである。なお、店員はお釣りに紙幣を使用することはない。

Input

入力にはいくつかのテストケースが含まれる。

それぞれのテストケースは 2 行から構成される。 1 行目には Mr. Bill の支払い金額を円単位で表した 1 つの整数が含まれている。 2 行目には 4 つの整数が含まれており、それらは順に財布の中にある 10 円玉、50 円玉、100 円玉、500 円玉の枚数をそれぞれ表す。

支払い金額は常に 10 円単位である。 すなわち、支払い金額の一円の位は常に 0 である。 また財布の中に、同じ種類の硬貨は最大で 20 枚までしかないと仮定してよい。 支払いが不可能なケースが入力中に与えられることはない。

入力の終了は単一の 0 を含む行によって表される。

Output

それぞれのテストケースについて、Mr. Bill が使用すべき硬貨の種類と枚数を出力せよ。

出力の各行には 2 つの整数 ci 、ki が含まれる。これは支払いの際に ci 円玉を ki 枚使用することを意味している。
複数種類の硬貨を使用する場合は、ci の小さいほうから順に、必要な行数だけ出力を行うこと。 下記の出力例を参考にせよ。

なお、出力には余計なスペースを含めてはならない。 連続するテストケースの間は空行で区切ること。

Sample Input

160
1 1 2 0
160
1 0 2 10
0

Output for the Sample Input

10 1
50 1
100 1

10 1
100 2

Solution in JAVA (judge verdict: Accepted)

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;

public class Main {

	public static void main(String[] args) throws IOException {
		// TODO ?????????????????????????????????????????????
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		int tcase = 0;
		while(true){
			int price = Integer.parseInt(br.readLine());
			if(price == 0){
				break;
			}
			
			if(tcase != 0){
				System.out.println();
			}
			String[] tmpArray = br.readLine().split(" ");

			int c10 = Integer.parseInt(tmpArray[0]);
			int c50 = Integer.parseInt(tmpArray[1]);
			int c100 = Integer.parseInt(tmpArray[2]);
			int c500 = Integer.parseInt(tmpArray[3]);

			//?´???´?????????
			int minimumCoins = Integer.MAX_VALUE;
			int res10 = 0, res50 = 0, res100 = 0, res500 = 0;
			for(int i = 0; i <= c10; i++){
				for(int j = 0; j <= c50; j++){
					for(int k = 0; k <= c100 ; k++ ){
						for(int l = 0; l <= c500; l++){
							if(i*10 + j*50 + k*100 + l*500 >= price){
								int numOfCoins = i + j + k + l;
								Change change = new Change(i*10 + j*50 + k*100 + l*500 - price);
//								System.out.println(i*10 + j*50 + k*100 + l*500 - price);
								if(change.isAvailable(i, j, k, l)){
//									System.out.println("Available");
									minimumCoins = Math.min(minimumCoins, (c10+c50+c100+c500) - numOfCoins + change.numOfCoins());
//									System.out.println("coins "+ ((c10+c50+c100+c500) - numOfCoins + change.numOfCoins()));
									res10 = i; res50 = j; res100 = k; res500 = l;
								}
 							}
						}
					}
				}
			}

			if(res10 != 0)System.out.println("10 "+res10);
			if(res50 != 0)System.out.println("50 "+res50);
			if(res100 != 0)System.out.println("100 "+res100);
			if(res500 != 0)System.out.println("500 "+res500);
			
			tcase++;
		}
	}

}

class Change {
	int c10, c50, c100, c500;

	public Change(int p){
		c500 = p/500;
		p %= 500;
		c100 = p/100;
		p %= 100;
		c50 = p/50;
		p %= 50;
		c10 = p/10;
	}

	int numOfCoins(){
//		System.out.println("change coins "+ (c10 + c50 + c100 + c500));
		return c10 + c50 + c100 + c500;
	}

	boolean isAvailable(int c10, int c50, int c100, int c500){
//		if((this.c10 == 0 || this.c10 != c10) && (this.c50 == 0 || this.c50 != c50) && 
//				(this.c100 == 0 || this.c100 != c100) && (this.c500 == 0 || this.c500 != c500)){
		if(this.c10*c10 == 0 && this.c50*c50 == 0 && this.c100*c100 == 0 && this.c500*c500 == 0){
			return true;
		}
		else {
			return false;
		}
	}
}