SRM 510 DIV1 Medium TheLuckyGameDivOne

http://apps.topcoder.com/stat?c=problem_statement&pm=11463&rd=14439

問題

10進法表現に4と7のみしか現れない数をlucky numberと呼ぶ。
今、positive上に[a,b] (1<=a<=b<=10^10)の区間がある。
初めに、Johnは[a,b]に含まれ、長さがjLen(1<=jLen<=b-a+1)である連続した区間[ja,jb]を選ぶ。
次に、Brusは[ja,jb]に含まれ、長さがbLen(1<=bLen<=b-a+1)である連続した区間[ba,bb]を選ぶ。
最後に、[ba,bb]に含まれるlucky numberの数を数える。
Johnはできる限りその数が大きくなるように選び、
Brusはできる限りその数が小さくなるように選ぶとき、その数を答えろ

回答

[a,b]に含まれるlucky numberの数はたかだか sum (map (2^) [1..10]) == 2046 であって、つまりその二乗*α程度なら問題ない。
ここで、戦略を考える。
Brusはできるだけ少なくするのに、lucky number[i] == ba+1 となるところを選ぶ戦略ができる。(たぶん)
ただし、それが何も選べない場合もあって、そういう場合はどこでも同じだと思う。
Johnはできるだけ多くするのに、 ja == lucky number[i] - bLen + 1 となる所を選ぶ戦略ができる。たぶん。できるだけ含めないといけないlucky numberを多くする、的な。
さて、この戦略を全てのlucky numberに対して試し、それぞれの数がわかればいい。
数を数える方法は下記参照

コメント

初めて?かもしれないけど、DIV1 Mediumが自力で解けた。ただし、時間はかかりまくって167.06ptだけど。
結構、何番目か、を得るのに苦労した。だが、upper_boundが使えると思いついて、とてもいいと思った。

vector<T> v;
//vに対象となるものを全てpush_backしてソートしておく
int count(T x) {
    return upper_bound(all(v), x) - v.begin();
    //対象となるもの以下にいくつの要素(要素の個数)があるかを返す
}
count(r) - count(l-1) //区間[l,r]の場合
count(r-1) - count(l-1) //区間[l,r)の場合

コード

#include <string>
#include <vector>
#include <algorithm>
#include <set>
#include <map>
#include <queue>
#include <iostream>
#include <sstream>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <cstring>
#define rep(i,n) for(int (i)=0;(i)<(int)(n);++(i))
#define rer(i,l,u) for(int (i)=(int)(l);(i)<=(int)(u);++(i))
#define reu(i,l,u) for(int (i)=(int)(l);(i)<(int)(u);++(i))
#define aut(v, x) __typeof(x) v = (x)
#define each(it,o) for(aut(it, (o).begin()); it != (o).end(); ++ it)
#define all(o) (o).begin(), (o).end()
#define pb(x) push_back(x)
#define mp(x,y) make_pair((x),(y))
#define mset(m,v) memset(m,v,sizeof(m))
using namespace std;
typedef long long ll; typedef vector<int> vi; typedef pair<int,int> pii; typedef vector<pii> vpii;
const int INF = 0x3f3f3f3f; const ll INFL = 0x3f3f3f3f3f3f3f3fLL;

struct TheLuckyGameDivOne {
	vector<ll> v;
	int count(ll x) {
		return upper_bound(all(v), x) - v.begin();
	}
	int find(long long a, long long b, long long jLen, long long bLen) {
		int r = 0;
		rer(i, 1, 10) rep(j, 1<<i) {
			ll x = 0;
			rep(k, i) x = x * 10 + (!((j>>k)&1) ? 4 : 7);
			v.pb(x);
		}
		sort(all(v));
		rep(i, 100) cout << i << ": " << count(i) << endl;
		each(x, v) {
			if(!(a <= *x && *x <= b)) continue;
			ll t = *x - bLen + 1;
			if(t < a) t = a;
			ll u = t + jLen - 1;
			if(u > b) continue;
			int l = INF;
			l = min(l, count(t+bLen-1) - count(t-1));
			each(x2, v) {
				if(!(t <= *x2 && *x2 <= u)) continue;
				ll t2 = *x2 + 1;
				ll u2 = t2 + bLen - 1;
				if(u2 > u) continue;
				l = min(l, count(u2) - count(t2-1));
			}
			if(l != INF) r = max(r, l);
		}
		return r;
	}
};