SRM510 Div1Easy TheAlmostLuckyNumbersDivOne

http://community.topcoder.com/stat?c=problem_statement&pm=11461

どう考えても本番で書けないクソ解法なのでコードの流れだけ
方針として、b以下のAlmostLuckyNumberの数(以下AL数)からa-1以下のAL数を引くことを考えます。

  • bを扱いやすいように配列に入れる(init)
  • bより桁の小さいAL数をカウント(\displaystyle \sum_{i=0}^{}2^i(8i+1))
  • bと桁が同じで、b以下であるAL数を求める(count)

ex. b=1234

  1. 1~999 のAL数をカウント
  2. 1000~1199 のAL数を…
  3. 1200~1229 の…
  4. 1230~1234 …

これでb以下のAL数が全て求まったので、a-1についても同様にやります。
この解法の悪いところは、自分でコーナーケース(count中の分岐)を増やすところです。サンプルがよわよわだと詰みます。

#include <bits/stdc++.h>
using namespace std;

class TheAlmostLuckyNumbersDivOne {
public:
    vector<int> init(long long n) {
       vector<int> v;
       while(n>0){
           v.push_back(n%10);
           n/=10;
       }
       reverse(v.begin(),v.end());
       return v;
    }

    long long count(vector<int> v) {
        int S=v.size();
        long long ret=0;
        for(int i=0;i<S;i++){
            if(i==0&&v[i]==1&&S!=1) continue;
            int unlucky=0;
            for(int j=0;j<i;j++){
                int n=v[j];
                if(n!=4&&n!=7) unlucky++;
            }
            if(i==S-1){
                for(int j=(S==1?1:0);j<=v[i];j++){
                    if(unlucky==0) ret++;
                    else if(unlucky==1&&(j==4||j==7)) ret++;
                }
            }else{
                for(int j=(i==0?1:0);j<=v[i]-1;j++){
                    if(j!=4&&j!=7) unlucky++;
                    if(unlucky==0) ret+=pow(2,(S-i-1))+8*(S-i-1)*pow(2,(S-i-2));
                    else if(unlucky==1) ret+=pow(2,(S-i-1));
                    if(j!=4&&j!=7) unlucky--;
                }
            }
        }
        return ret;
    }

    long long find( long long a, long long b ) {
       vector<int>low=init(--a);
       int L=low.size();
       vector<int>high=init(b);
       int H=high.size();

       long long ans=0;
       for(int i=1;i<H;i++) ans+=pow(2,i-1)*(8*i+1);
       ans+=count(high);
       for(int i=1;i<L;i++) ans-=pow(2,i-1)*(8*i+1);
       ans-=count(low);
       return ans;
    }
};