AT2272 [ARC066B] Xor Sum

https://www.luogu.com.cn/problem/AT2272

首先要注意到xor是不进位的加法

所以加法可以表示成 a + b = ( a ⊕ b ) + ( ( a & b ) < < 1 ) a+b=(a\oplus b)+((a\&b)<<1) a+b=(ab)+((a&b)<<1)
可以得到 a + b ≥ a ⊕ b a+b\ge a\oplus b a+bab
假设 a ≤ b a\le b ab
那么我们考虑设 f [ i ] [ j ] f[i][j] f[i][j]表示考虑 a , b a,b a,b的前 i i i为,和为 j j j的方案数

那么转移这一位有3种情况 ( 0 , 0 ) ( 0 , 1 ) ( 1 , 1 ) (0,0)(0,1)(1,1) (0,0)(0,1)(1,1)
对应状态转移为

  • j − > 2 j j->2j j>2j
  • j − > 2 j + 1 j->2j+1 j>2j+1
  • j − > 2 ( j + 1 ) j->2(j+1) j>2(j+1)

把这个翻过来就可以得到方程
f [ i ] [ j ] = f [ i − 1 ] [ j 2 ] + f [ i − 1 ] [ j − 1 2 ] + f [ i − 1 ] [ j − 2 2 ] f[i][j]=f[i-1][\frac{j}{2}]+f[i-1][\frac{j-1}{2}]+f[i-1][\frac{j-2}{2}] f[i][j]=f[i1][2j]+f[i1][2j1]+f[i1][2j2]

然后把第一维滚掉就是一个 O ( l o g n ) O(log n) O(logn)的递归式了

code:

#include<bits/stdc++.h>
#define ll long long
#define mod 1000000007
using namespace std;
ll n;
map<ll, ll> f;
ll dp(ll n) {
    if(f.find(n) != f.end()) return f[n];
    return f[n] = (dp(n / 2) + dp((n - 1) / 2) + dp(n / 2 - 1)) % mod;
}
int main() {
    f[0] = 1, f[1] = 2;
    scanf("%lld", &n);
    printf("%lld", dp(n));
    return 0;
}

posted @ 2021-10-13 07:15  lahlah  阅读(50)  评论(0编辑  收藏  举报