AT2272

前言

这题让我知道了,大佬写证明,蒟蒻找规律。

分析

借鉴于此
首先是一个知识,\(a+b \ge a\) \(xor\) \(b\)
\(u\le v\)的时候,如果\(v\)不超出范围,那么\(u\)一定不会超出,设\(dp_{i,j}\)表示考虑了当前\(a,b\)的第\(i\)位,且\(v=a+b=j\)的方案数。
然后对于\(i\)\(i-1\)的转移,令\(j_1\)表示\(i-1\)时的\(j\),这时\(a,b\)的第\(i\)位只会有三种情况。

  • \(j_1+1<<1=j\)表示第\(i\)位上都放了1
  • \(j_1<<1=j\)表示第\(i\)位上都放了0
  • \(j_1<<1|1=j\)表示第\(i\)位上一个放了1,另一个放了0
    可以发现状态只跟上一层有关,于是压去一维。
    但发现这个数组还是开不下,于是就用到了std::map,第一次发现map还能拿来做dp。
    其实这个题很好的说明了dp的优点,它和暴力很像但是比暴力快,快在了什么地方,就是它用了一个状态就能表示暴力算了很多次的东西,大大减少了不必要的计算。
#include<cstdio>
#include<map>
#define ll long long
using namespace std;
const int Mod=1e9+7;
map<ll,ll> dp;
ll dfs(ll x){
    if(dp[x])return dp[x];
    return dp[x]=(dfs(x>>1)+dfs(x-1>>1)+dfs(x-2>>1))%Mod;
}
int main(){
    ll n;
    scanf("%lld",&n);
    dp[0]=1;
    dp[1]=2;
    ll res=dfs(n)%Mod;
    printf("%lld\n",res);
}
posted @ 2020-05-10 18:27  An_Fly  阅读(147)  评论(0编辑  收藏  举报