問題
http://community.topcoder.com/stat?c=problem_statement&pm=12049&rd=14738
整数が与えられる。
整数が偶数のときは2で割り、奇数であれば1を引くことができる。
整数の範囲とある数が与えられた時、
その整数の範囲内である数が存在する数が何通りあるか求める。
解き方
数が10^18のため、範囲中の全ての数を全探索で求めることはできない。
そのため、法則がないか数を列挙してみる。
ここで状態遷移図を用いてみる。
1)kが偶数のとき
K←2K←2K+1←4K+2←8K+4
←4K+3
←4K←8K←16K
←8K+1
←4K+1←8K+2
←K+1←2K+2←4K+4←8K+8
←4K+5
←2K+3←4K+6→4K+7
2)kが奇数のとき
K←2K←2K+1←4K+2←8K+4
←4K+3
←4K←8K←16K
←8K+1
←4K+1←8K+2
つまり、以下の法則が導ける。
kが偶数のときは
K~K+1,2K~2K+3、4K~4K+7
kが奇数のときは
K、2K~2K+1、4K~4K+3
最小はKの倍数、最大はKもしくはK+1から始まり2倍+1となる。
コード
class KleofasTail {
public:
long long calc(long long K,long long B){
long long ans=0,low=K,high=K;
if(K%2==0)high++;
while(low<=B){
ans+=min(high,B)-low+1;
low=2*low;
high=2*high+1;
}
return ans;
}
long long countGoodSequences(long long K, long long A, long long B) {
if(K==0)return B-A+1;
return calc(K,B)-calc(K,A-1);
}
};
public:
long long calc(long long K,long long B){
long long ans=0,low=K,high=K;
if(K%2==0)high++;
while(low<=B){
ans+=min(high,B)-low+1;
low=2*low;
high=2*high+1;
}
return ans;
}
long long countGoodSequences(long long K, long long A, long long B) {
if(K==0)return B-A+1;
return calc(K,B)-calc(K,A-1);
}
};
using namespace std;
#define FORE(i,d,e) for(int i=d;i<e;i++)
#define FOR(i,s,e) for (int i = int(s); i != int(e); i++)
#define FORIT(i,c) for (typeof((c).begin()) i = (c).begin(); i != (c).end(); i++)
#define ISEQ(c) (c).begin(), (c).end()
class KleofasTail {
public:
long long countGoodSequences(long long K, long long A, long long B) {
if(K==0)return B-A+1;
long long ret=0;
long long e= K%2==1 ? 1 : 2;
long long cur=K;
while(cur<=B){
long long minx=max(cur,A);
long long maxx=min(cur+e-1,B);
ret+=max(0LL,maxx-minx+1);
cur*=2,e*=2;
}
return ret;
}
};
#define FORE(i,d,e) for(int i=d;i<e;i++)
#define FOR(i,s,e) for (int i = int(s); i != int(e); i++)
#define FORIT(i,c) for (typeof((c).begin()) i = (c).begin(); i != (c).end(); i++)
#define ISEQ(c) (c).begin(), (c).end()
class KleofasTail {
public:
long long countGoodSequences(long long K, long long A, long long B) {
if(K==0)return B-A+1;
long long ret=0;
long long e= K%2==1 ? 1 : 2;
long long cur=K;
while(cur<=B){
long long minx=max(cur,A);
long long maxx=min(cur+e-1,B);
ret+=max(0LL,maxx-minx+1);
cur*=2,e*=2;
}
return ret;
}
};