Hatena::Grouptopcoder

naoya_t@topcoder RSSフィード

2009-01-17

SRM365 Div1 Easy: PointsOnCircle

| 12:52 | SRM365 Div1 Easy: PointsOnCircle - naoya_t@topcoder を含むブックマーク はてなブックマーク - SRM365 Div1 Easy: PointsOnCircle - naoya_t@topcoder SRM365 Div1 Easy: PointsOnCircle - naoya_t@topcoder のブックマークコメント

300点問題・・・普通にやってたらTLE

typedef long long ll;
#define sz(a)  int((a).size())
#define pb  push_back
#define all(c)  (c).begin(),(c).end()
#define tr(c,i)  for(typeof((c).begin()) i=(c).begin(); i!=(c).end(); i++)
#define rep(var,n)  for(int var=0;var<(n);var++)
#define found(s,e)  ((s).find(e)!=(s).end())

ll primes[44721];// 357768 bytes
int primes_cnt;

int e_sieve(int till)
{
  vector<bool> sieve(till+1,true);
  primes_cnt = 0;

  sieve[2] = true;
  primes[primes_cnt++] = 2;

  for (int prime=3;;) {
    primes[primes_cnt++] = prime;
    for (int i=prime*3;i<=till;i+=(prime*2)) sieve[i] = false;

    int next_prime = -1;
    for (int j=prime+2; j<=till; j+=2) {
      if (sieve[j]) { next_prime = j; break; }
    }

    if (next_prime == -1) break;
    prime = next_prime;
  }

  return primes_cnt;
}

map<int,int> prime_factors(int n)
{
  map<int,int> factors;
  for (int i=0; i<primes_cnt; i++) {
    int prime = primes[i];
    while (n % prime == 0) {
      if(found(factors,prime)) factors[prime]++;
      else factors[prime]=1;
      n /= prime;
    }
    if (n==1) return factors;
  }
  factors[n] = 1; return factors;
}

vector<ll> divisors(map<int,int> pfs){
  set<ll> s;
  s.insert(1LL);
  
  tr(pfs,it){
    ll prime=(ll)it->first,mx=it->second,n=1LL;
    set<ll> t(all(s));
    rep(i,mx) {
      n *= prime;
      tr(s,st) t.insert(n*(*st));
    }
    s=t;
  }
  vector<ll> ans(all(s));
  return ans;
}

class PointsOnCircle {
 public:
  long long count(int r) {
    // 素数を準備
    e_sieve((int)sqrt(r));

    // rを素因数分解; 2000000000 => { 2 => 10, 5 => 9 } 
    map<int,int> pfs=prime_factors(r);

    // r^2を素因数分解、というかrの結果を2乗。
    // 4で割って余りが出るものだけにしたいので、
    // ここで 2^k の係数を1以下に限定する。
    // => { 2 => (20→)1, 5 => 18 } 
    tr(pfs,it){
      it->second *= 2;
      if(it->first==2) it->second=min(2,it->second);
    }
    // 素因数分解の結果から約数を求める
    vector<ll> ds = divisors(pfs);

    // 4*(d1(n)-d3(n))を求める
    ll c=0LL;
    tr(ds,it){
      int rm=(*it)%4;
      if(rm==1) c++;
      else if(rm==3) c--;
    }
    return c<<2;
  }
};
トラックバック - http://topcoder.g.hatena.ne.jp/n4_t/20090117