Codeforces Round #194 Div1C Lucky Tickets

問題

チケットは8ケタの、0~9の数字で番号が振られています(leading zeroを含みます)。
k-luckyとは、その8ケタの番号に+-*やカッコをつけたりして、計算結果がkになるようにできるような数字です。
たとえば、
"224201016"は
( - 2 - (2 + 4)) * (2 + 0) + 1016 = 1000
なので、1000-luckyです。

k-luckyなチケット番号を、m個出力してください。

制約
0 ≤ k ≤ 10^4, 1 ≤ m ≤ 3·10^5


解法
正解者がDやEよりも少ない超地雷問だったっぽいです。
解法は極めてトリッキーで、こんなんコンテスト中に思いつくわけねーだろって感じです。


8ケタのチケット番号を、4ケタずつに区切って考えます。
ところでマイナスをいくらでもつけていいので、数字からNが作れる場合は-Nも作れます。
というわけで、上4ケタで作れる数字を片っ端から列挙していき(これをxとします)、
下4ケタを|x-k|とすれば、とりあえずk-luckyな番号が作れます。
(|x-k|の値が同じになるxが2つあるのと、|x-k|が4ケタに収まらない場合だけ注意が必要です)

4ケタの数字1つから平均して60以上の数字が作れるので、上4ケタから対応する下4ケタを当てていくスタイルだけで600000くらいの番号が作り出せる計算で、制約のmより十分大きくなっています。


プログラム

#include<iostream>
#include <fstream>
#include <stdio.h>
#include <stdlib.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include<string>
#include<vector>
#include<cmath>
#include<stack>
#include<queue>
#include<sstream>
#include<algorithm>
#include<map>
#include<complex>
using namespace std;


#define li			long long int
#define rep(i,to)	for(li i=0;i<((li)(to));i++)
#define repp(i,start,to)	for(li i=(li)(start);i<((li)(to));i++)
#define pb			push_back
#define sz(v)		((li)(v).size())
#define bgn(v)		((v).begin())
#define eend(v)		((v).end())
#define allof(v)	(v).begin(), (v).end()
#define dodp(v,n)		memset(v,(li)n,sizeof(v))
#define bit(n)		(1ll<<(li)(n))
#define mp(a,b)		make_pair(a,b)
#define rin	rep(i,n)
#define EPS 1e-10
#define ETOL 1e-8
#define MOD 1000000007
#define p2(a,b)		cout<<a<<"\t"<<b<<endl
#define p3(a,b,c)		cout<<a<<"\t"<<b<<"\t"<<c<<endl

vector<li> search(li num, li keta){
	vector<li> res;
	res.pb(num);
	res.pb(-num);
	
	if(keta>1){
		li l=10;
		for(int i=1; i<keta; i++, l*=10){
			vector<li> v1=search(num%l, i);
			vector<li> v2=search(num/l, keta-i);
			rep(j,sz(v1)){
				rep(k,sz(v2)){
					res.pb(v1[j]+v2[k]);
					res.pb(v1[j]*v2[k]);
				}
			}
		}
	}
	
	sort(allof(res));
	vector<li>::iterator it=unique(allof(res));
	res.erase(it,res.end());
	
	return res;
}

int main(){
	li k,m;
	cin>>k>>m;
	
	rep(i,10000){
		vector<li> is=search(i,4);
		vector<li> exist;
		
		rep(j,sz(is)){
			if(is[j]>=0 && is[j]<10000 && find(allof(exist), abs(k-is[j]))==exist.end() && abs(k-is[j])<10000){
				printf("%04I64d%04I64d\n", i, abs(k-is[j]));
				exist.pb(abs(k-is[j]));
				m--;
				if(m<=0)return 0;
			}
		}
	}
	return 0;
}