D. Infinite Set
思路
二进制下,2x+1相当于进一位然后+1,4x相当于进两位,令DP[i]表示进i位的情况数,则有递推方程dp[i] = dp[i - 1] + dp[i - 2],然后对于每个数,若k位该数能进的最大位数,则情况数为dp[0]~dp[k]的总和,用还需预处理出前缀和。然后对最开始的数组去重,接着算出每个数能进的位数,就做完了
Code
#include <bits/stdc++.h>
#pragma GCC optimize(2)
#define debug freopen("_in.txt", "r", stdin);
// #define debug freopen("_in.txt", "r", stdin), freopen("_out.txt", "w", stdout);
typedef long long ll;
typedef unsigned long long ull;
using namespace std;
const ll INF = 0x3f3f3f3f3f3f3f3f;
const ll maxn = 3e5 + 10;
const ll maxm = 1e4 + 10;
const ll mod = 1e9 + 7;
const double pi = acos(-1);
const double eps = 1e-8;
ll n, p;
ll arr[maxn], brr[maxn], pre[maxn];
map<ll, ll> mp;
ll dp[maxn];
int main()
{
// debug;
scanf("%lld%lld", &n, &p);
dp[0] = 1, dp[1] = 1, dp[2] = 2;
pre[0] = 1;
pre[1] = 2;
for (ll i = 2; i <= p + 10; i++)
{
dp[i] = dp[i - 1] + dp[i - 2];
dp[i] %= mod;
pre[i] = pre[i - 1] + dp[i];
pre[i] %= mod;
}
ll cnt = 0;
for (ll i = 1; i <= n; i++)
{
scanf("%lld", &arr[i]);
mp[arr[i]] = 1;
}
sort(arr + 1, arr + n + 1);
for (ll i = 1; i <= n; i++)
{
ll flag = 1, num = arr[i];
while (num)
{
if (num & 1)
{
num >>= 1;
}
else if (num % 4 == 0)
{
num >>= 2;
}
else
break;
if (mp[num])
{
flag = 0;
break;
}
}
if (flag)
{
brr[++cnt] = arr[i];
}
}
ll ans = 0;
for (ll i = 1; i <= cnt; i++)
{
ll len = 0;
while ((1ll << len) <= brr[i])
len++;
if (p < len)
continue;
ans += pre[p - len];
ans %= mod;
}
printf("%lld\n", ans);
}