Problem:
ネットカフェ

あなたはネットカフェを経営しています。今日あなたは、顧客に指摘され続けている問題を解決しようと取り組んでいます。その問題とは、店舗の本棚の単行本が巻数順に並んでおらず、目的の単行本を探しだすのが面倒だという苦情です。

あなたの店舗で一番巻数の多い単行本は「名探偵 赤ベコ」（通称「赤ベコ」）です。あまりに長編なので、特別な本棚を「赤ベコ」のために用意しました。

単行本の各巻の重さと厚さは様々で、本棚の各段の幅と、各段に並べることができる本の重さの上限も様々です。あなたは、次の条件を満足するように本棚に本を並べることにしました。

1 巻からある巻までの「赤ベコ」が本棚に並んでいる。

それぞれの段には、巻数順に（途中で抜けている巻がないように）本が並ぶ。

各段に並べる本の重さの合計が、その段で定められた重さの上限を超えない。

各段に並べる本の厚さの合計が、その段の幅を超えない。

これらの条件を満たしたとき，この本棚に最大で何巻まで「赤ベコ」を並べることができるかを求めるプログラムを作成してください。

入力

入力は以下の形式で与えられる。

M N
w1 t1
w2 t2
:
wM tM
c1 b1
c2 b2
:
cN bN

最初の１行に「赤ベコ」の巻数 M (1 ≤ M ≤ 200000) と本棚の段数 N (1 ≤ N ≤ 15) が与えられる。続く M 行に、「赤ベコ」の単行本 i 巻目の重さ wi (1 ≤ wi ≤ 100) と厚さ ti (1 ≤ ti ≤ 100) を表す整数が与えられる。続く N 行に、本棚の i 段目の重さの上限 ci (1 ≤ ci ≤ 108)と幅 bi (1 ≤ bi ≤ 108) を表す整数が与えられる。

出力

本棚に並べることができる最大の「赤ベコ」巻数を１行に出力する。

入出力例

入力例１

3 4
2 2
3 3
4 4
3 3
4 4
1 1
2 2

出力例１

3

入力例２

2 2
1 2
2 1
2 1
2 1

出力例２

0

入力例３

3 2
1 2
2 2
2 1
3 3
2 2

出力例３

2

入力例４

3 2
1 2
2 1
2 2
2 2
3 3

出力例４

3

Solution in C# (judge verdict: Accepted)

using System;
using static System.Math;
public class hello
{
	static int dpmax;
	public static void Main()
	{

		string[] line = Console.ReadLine().Trim().Split(' ');
		var m = int.Parse(line[0]);
		var n = int.Parse(line[1]);
		dpmax = 1 << n;
		var book = getData(m);
		var s = getData(n);
		var book2 = getCsum(book, m);
		var dp = new int[dpmax];
		for (int i = 1; i < dpmax; i++) dp[i] = -10;
		dp[0] = -1;
		var ans = getAns(dp, book2, m, s, n);
		Console.WriteLine(ans == 0 ? 0 : ans + 1);
	}
	static int getAns(int[] dp, int[,] book2, int m, int[,] s, int n)
	{
		var ans = 0;
		for (int i = 0; i < dpmax; i++)
		{
			if (dp[i] == m - 1) return m - 1;
			for (int j = 0; j < n; j++)
			{
				if (dp[i] != -10)
					if (((i >> (n - j - 1)) & 1) == 0)
					{
						var ww = i | (1 << (n - j - 1));
						var t = goBS(book2, m, s, n, j, dp[i] + 1);
						if (t != -1)
						{
							dp[ww] = Max(dp[ww], t);
							ans = Max(ans, dp[ww]);
						}
					}
			}
		}
		return ans;
	}
	static int goBS(int[,] book2, int m, int[,] s, int n, int t, int next)
	{
		if ((book2[m, 0] - book2[next, 0] <= s[t, 0]) && (book2[m, 1] - book2[next, 1] <= s[t, 1]))
			return m - 1;
		if ((book2[next + 1, 0] - book2[next, 0] > s[t, 0]) | (book2[next + 1, 1] - book2[next, 1] > s[t, 1]))
			return -1;
		var ok = next;
		var ng = m - 1;
		while (ng - ok > 1)
		{
			var mid = ok + (ng - ok) / 2;
			if ((book2[mid + 1, 0] - book2[next, 0] <= s[t, 0]) && (book2[mid + 1, 1] - book2[next, 1] <= s[t, 1]))
				ok = mid;
			else ng = mid;
		}
		return ok;
	}
	static int[,] getCsum(int[,] a, int n)
	{
		var ans = new int[n + 1, 2];
		for (int i = 0; i < n; i++)
		{
			ans[i + 1, 0] = ans[i, 0] + a[i, 0];
			ans[i + 1, 1] = ans[i, 1] + a[i, 1];
		}
		return ans;
	}
	static int[,] getData(int n)
	{
		var ans = new int[n, 2];
		for (int i = 0; i < n; i++)
		{
			string[] line = Console.ReadLine().Trim().Split(' ');
			ans[i, 0] = int.Parse(line[0]);
			ans[i, 1] = int.Parse(line[1]);
		}
		return ans;
	}
}