SRM 508 Div1 Medium YetAnotherORProblem

shioshiotaさんのブログ見てようやく理解できた。。。
id:shioshiota:20110613:1307955077

問題

数列R[i](0≦i<n)が与えられる。
次の条件を満たすような数列がいくつあるか、mod 1000000009で求めよ。


A[0] + A[1] + … + A[n-1] = A[0] | A[1] | … | A[n-1]
かつ
A[i]≦R[i]

制約条件

n≦10
R[i]≦10^18

方針

まず、A[0],A[1],...,A[n-1]のiビット目のうち、1になっているものはただ一つだけである。
(そうでなければA[0] + A[1] + … + A[n-1] > A[0] | A[1] | … | A[n-1]になるため)



A[j]を、上位ビットiから、A[j]のうち高々1つどれを1にするかの決定していく。
R[j]のiビット目が1で、A[j]のiビット目を0にすると、A[j]のi-1ビット目以下は全て自由に決定できる。

dp[i][mask]を上からiビットまでを見て、集合maskのビットを自由に決定できるような数列A(のiビット目まで)の場合の数とすると、n個のAのうちどのiビット目を1にするかでテーブルの更新ができてDPできる。


ビットを1にできるA[j]は、集合maskに含まれているjまたは、R[j]のiビット目が1であるようなjである。

ソースコード

const int mod = 1000000009;

class YetAnotherORProblem {
  public:
  int countSequences(vector<long long> R) {
    int n=R.size(), dp[65][1<<10]={}, ans=0;
    dp[62][0]=1;

    for(int i=62;i>=0;i--)rep(mask,1<<n){
        
        int nmask=mask;
        //A[0]〜A[n-1]のiビット目を全部0にする
        rep(k,n)if(R[k]&1ll<<i)nmask|=1<<k;
        if(i)(dp[i-1][nmask]+=dp[i][mask])%=mod;
        else (ans+=dp[i][mask])%=mod;

        //A[j]のi番目のビットを1にする
        rep(j,n){
          //maskにjが含まれているもしくはR[j]のiビット目が1の時だけA[j]のiビット目は1にできる。
          if(!(mask&1<<j)&&!(R[j]&1ll<<i))continue;
          
          nmask=mask;
          rep(k,n){
            //R[k]のiビット目が1のところを0にしたら、A[k]のi-1ビット目以下は自由になる。
            //(のでmaskにkを加える)
            if(j!=k&&(R[k]&1ll<<i))nmask|=1<<k;
          }
          if(i)(dp[i-1][nmask]+=dp[i][mask])%=mod;
          else (ans+=dp[i][mask])%=mod;
        }
      }
    return ans;
  }
};