[DP] Topcoder SRM 552 DIV1 Hard. HolyNumbers

fi,j 表示前 i 个质数,能组成小于等于 j 的方案数
转移简单,但是记忆化会爆内存
倒过来考虑, fi,j 表示用了后 i 个质数的方案数,那么当 p2i>j 时就可以用二分查找解决

// BEGIN CUT HERE  

// END CUT HERE  
#include <vector>  
#include <list>  
#include <map>  
#include <set>  
#include <deque>  
#include <stack>  
#include <bitset>  
#include <algorithm>  
#include <functional>  
#include <numeric>  
#include <utility>  
#include <sstream>  
#include <iostream>  
#include <iomanip>  
#include <cstdio>  
#include <cmath>  
#include <cstdlib>  
#include <ctime>  
#include <queue>
#include <assert.h>
#include <cstring>
#include <tr1/unordered_map>
#define pb push_back
#define fi first
#define se second

using namespace std;
using namespace tr1;

typedef long long ll;
typedef pair<int,ll> par;

const int N=1000010;

int p[N];

inline void Pre(int n){
  for(int i=2;i<=n;i++){
    if(!p[i]) p[++*p]=i;
    for(int j=1;j<=*p && 1LL*p[j]*i<=n;j++){
      p[p[j]*i]=1;
      if(i%p[j]==0) break;
    }
  }
}

int ttt;

ll dp(int n,ll m){
  if(n>*p || p[n]>m) return 1;
  if(1LL*p[n]*p[n]>m) return upper_bound(p+1,p+1+(*p),m)-p-n+1;
  ll ret=dp(n+1,m);
  for(ll i=p[n];i<=m;i*=1LL*p[n]*p[n])
    ret+=dp(n+1,m/i);
  return ret;
}

class HolyNumbers{  
public:  
  long long count(long long upTo, int maximalPrime) {  
    memset(p,0,sizeof(p)); Pre(maximalPrime);
    return dp(1,upTo);
  }  

// BEGIN CUT HERE
    public:
    void run_test(int Case) { if ((Case == -1) || (Case == 0)) test_case_0(); if ((Case == -1) || (Case == 1)) test_case_1(); if ((Case == -1) || (Case == 2)) test_case_2(); if ((Case == -1) || (Case == 3)) test_case_3(); if ((Case == -1) || (Case == 4)) test_case_4(); }
    private:
    template <typename T> string print_array(const vector<T> &V) { ostringstream os; os << "{ "; for (typename vector<T>::const_iterator iter = V.begin(); iter != V.end(); ++iter) os << '\"' << *iter << "\","; os << " }"; return os.str(); }
    void verify_case(int Case, const long long &Expected, const long long &Received) { cerr << "Test Case #" << Case << "..."; if (Expected == Received) cerr << "PASSED" << endl; else { cerr << "FAILED" << endl; cerr << "\tExpected: \"" << Expected << '\"' << endl; cerr << "\tReceived: \"" << Received << '\"' << endl; } }
    void test_case_0() { long long Arg0 = 10LL; int Arg1 = 100; long long Arg2 = 8LL; verify_case(0, Arg2, count(Arg0, Arg1)); }
    void test_case_1() { long long Arg0 = 10LL; int Arg1 = 3; long long Arg2 = 5LL; verify_case(1, Arg2, count(Arg0, Arg1)); }
    void test_case_2() { long long Arg0 = 123LL; int Arg1 = 12; long long Arg2 = 32LL; verify_case(2, Arg2, count(Arg0, Arg1)); }
    void test_case_3() { long long Arg0 = 123LL; int Arg1 = 456; long long Arg2 = 88LL; verify_case(3, Arg2, count(Arg0, Arg1)); }
    void test_case_4() { long long Arg0 = 123456789LL; int Arg1 = 12345; long long Arg2 = 25994500LL; verify_case(4, Arg2, count(Arg0, Arg1)); }

// END CUT HERE

};  

// BEGIN CUT HERE  
int main()  
{  
  HolyNumbers ___test;  
  ___test.run_test(-1);  
  system("pause");  
}  
// END CUT HERE  
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值