バイトの競プロメモ

主に競技プログラミング

D - Xor Sum AtCoder Beginner Contest 050

問題概略
2つの整数u,v <= Nであって、a ^ b = u, a + b = v となるようなu,vが何通りあるか。

制約
N <= 10 ^18

解法
aとbを適当に選んで、出てきたu,vを数えていきたくなる。しかし、これでは重複してしまうし、メモできるような数ではない。
ある桁のビットが1,0の時に0,1にしてもu,vが等しいと気づく。
よって1,0 は許すが0,1は許さないという風にすれば、a,bに対してu,vを全単射的な対応を箚せられる。
a,bをメモ化再帰の桁DPで数え上げる。
a,bのビットは0,0 1,0 11の時の3通りがあり、f(s , x):=uvがsx以下の通りとすると、0,0の時にはf(s/2,x/2)に、1,1の時にはf(s-2/2,x/2)になる。という風に桁を減らしてu,vの合計がS,X以上にならないように遷移できる。s,xについてメモすれば出来る。

public static long rec(long s, long x) {
        if (s == 0) return 1;
        String key = s + "_" + x;
        if (map.containsKey(key)) return map.get(key);
        long res = 0;
        //00
        res = modSum(res, rec(s / 2, x / 2));
        if (s > 0 && x > 0) {
            //10
            res = modSum(res, (rec((s - 1) / 2, (x - 1) / 2)));
        }
        if (s > 1) {
            //11
            res = modSum(res, (rec((s - 2) / 2, x / 2)));
        }
        map.put(key, res);
        return res;
    }

    public static void solve() throws Exception {
        //longを忘れるなオーバーフローするぞ
        N = nl();
        System.out.println(rec(N, N));

    }