POJ 3149 Billing Tables

Description

In the world of telecommunications phone calls to different phone numbers have to be charged using different rate or different billing plan. International Carrier of Phone Communications (ICPC) has an antique billing table that determines which phone call has to be charged using which billing plan.

Each international phone number has 11 digits. The billing table has n lines. Each line specifies a range of prefixes of phone numbers like “7919 - 921”. This specification means that all phone numbers starting from 7919, 7920, and 7921 match this line. A billing plan name is specified for each prefix. To determine a billing plan for a call, the table is scanned from top to bottom and the first matching line determines the billing plan. If no match is found, the phone number is invalid and no billing plan is needed. A special billing plan named “invalid” (without quotes) is used as an alternative way to define invalid phone numbers. Some billing plans are used for quite differently looking phone numbers and their names may be specified on different lines in different places of the table.

ICPC’s billing table is old and contains many entries. Some of those entries may not be even used anymore. It is very hard to figure out which phone numbers each billing plan is actually used for. The ICPC’s management has reached a decision to transform this billing table into a more legible format. In this new format table consists of the lexicographically ordered list of simple prefixes (without the “-” range feature of the old format) with a billing plan name for each prefix. No prefix of this new billing table should be a prefix of any other prefix from the table. Thus, a simple dictionary lookup (binary search, for example) will be sufficient to figure out a billing plan for a given phone number. Finding all phone numbers for a given billing plan will also become quite a simple task. The number of lines in the new billing table should be minimized. Billing plan named “invalid” should not be present in the new billing table at all, since invalid phone numbers will be denoted by absence of the corresponding prefix in the new billing table.

Input

The first line of the input file contains a single integer number n (1 ≤ n ≤ 100) — the number of lines in the old billing table. The following n lines describe the old billing table with one rule on a line. Each rule contains four tokens separated by spaces — prefix A, minus sign (“-”), prefixB, and billing plan name. Prefixes contain from 1 to 11 digits each, and the billing plan name contains from 1 to 20 lower case letters.

Further, let us denote with |A| the number of digits in the prefix A. It is true that 1 ≤ |B| ≤ |A| ≤ 11. Moreover, last |B| digits of prefix A form a string that is lexicographically equal or precedes B. Such pair of prefixes A and B matches all phone numbers with the first |A| − |B| digits matching the first digits of A and with the following |B| digits being lexicographically between the last |B| digits of A and B (inclusive).

Output

Write to the output file a single integer number k — the minimal number of lines that the new table should contain to describe the given old billing table. Then write k lines with the lexicographically ordered new billing table. Write two tokens separated by a space on each line — the prefix and the billing plan name. Note, that the prefix in the new billing table shall contain at least one digit.

If all phone numbers are invalid (every phone number has no matching line or matches line with billing plan “invalid”) then the output file should contain just number zero.

Sample Input

8
7919 - 921 cell
7921800 - 999 priv
1 - 1 usa
760 - 9 rsv
7928 - 29 rsv
7600 - 7899 spec
73 - 77 invalid
7 - 7 cis

Sample Output

35
1 usa
70 cis
71 cis
72 cis
76 rsv
77 spec
78 spec
790 cis
7910 cis
7911 cis
7912 cis
7913 cis
7914 cis
7915 cis
7916 cis
7917 cis
7918 cis
7919 cell
7920 cell
7921 cell
7922 cis
7923 cis
7924 cis
7925 cis
7926 cis
7927 cis
7928 rsv
7929 rsv
793 cis
794 cis
795 cis
796 cis
797 cis
798 cis

799 cis

把原本的电话号码转换成字典序的,建立一棵字典树,从后往前把范围插入即可。

#include<set>
#include<map>
#include<ctime>
#include<cmath>
#include<stack>
#include<queue>
#include<bitset>
#include<cstdio>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define rep(i,j,k) for (int i = j; i <= k; i++)
#define per(i,j,k) for (int i = j; i >= k; i--)
#define loop(i,j,k) for (int i = j;i != -1; i = k[i])
#define lson x << 1, l, mid
#define rson x << 1 | 1, mid + 1, r
#define fi first
#define se second
#define mp(i,j) make_pair(i,j)
#define pii pair<string,string>
using namespace std;
typedef long long LL;
const int low(int x) { return x&-x; }
const double eps = 1e-8;
const int INF = 0x7FFFFFFF;
const int mod = 1e8;
const int N = 5e5 + 10;
const int M = 1e3;
const int read()
{
	char ch = getchar();
	while (ch<'0' || ch>'9') ch = getchar();
	int x = ch - '0';
	while ((ch = getchar()) >= '0'&&ch <= '9') x = x * 10 + ch - '0';
	return x;
}
int n, root, tot;
int nt[N][10];
string l[M], r[M], s[M], na[N];
vector<pii> p;

int node()
{
	rep(i, 0, 9) nt[tot][i] = 0;
	na[tot] = "";	return tot++;
}

void insert(int &x, int pos, string L, string R, int l, int r, string g)
{
	if (!x) x = node();	
	if (pos >= L.size()) l = r = 0;
	if (!l && !r) { na[x] = g; return; }
	if (na[x] != "") rep(i, 0, 9) insert(nt[x][i], pos + 1, L, R, 0, 0, na[x]);
	na[x] = "";
	int ll = l ? L[pos] - '0' : 0, rr = r ? R[pos] - '0' : 9;
	if (ll == rr) { insert(nt[x][ll], pos + 1, L, R, l, r, g); return; }
	insert(nt[x][ll], pos + 1, L, R, l, 0, g);
	insert(nt[x][rr], pos + 1, L, R, 0, r, g);
	rep(i, ll + 1, rr - 1) insert(nt[x][i], pos + 1, L, R, 0, 0, g);
}

void dfs(int x)
{
	if (!x || na[x] != "") return;
	int flag = 0;
	string now = "";
	rep(i, 0, 9)
	{
		dfs(nt[x][i]);
		if (nt[x][i] && na[nt[x][i]] != "");
		{
			if (!flag) { now = na[nt[x][i]]; flag = 1; }
			else flag += now == na[nt[x][i]];
		}
	}
	if (flag == 10) na[x] = now;
}

void Dfs(int x,string id)
{
	if (!x) return;
	if (na[x] != ""&&x != root)
	{
		if (na[x] != "invalid") p.push_back(mp(id, na[x]));
	}
	else rep(i, 0, 9)  Dfs(nt[x][i], id + (char)('0' + i));
}

int main()
{
	while (scanf("%d", &n) != EOF)
	{
		rep(i, 1, n)
		{
			cin >> l[i] >> s[i] >> r[i] >> s[i];
			int k = l[i].size() - r[i].size();
			per(j, k - 1, 0) r[i] = l[i][j] + r[i];
		}
		root = 0; tot = 1;
		per(i, n, 1) insert(root, 0, l[i], r[i], 1, 1, s[i]);
		dfs(root);	
		p.clear(); Dfs(root, "");
		printf("%d\n", p.size());
		rep(i, 0, (int)(p.size() - 1)) cout << p[i].fi << " " << p[i].se << endl;
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值