位运算+线性dp
题目链接
由范围是2的p次方(p<2*10^5)
范围太大了
往位运算方面想
a数组集合都在S集合里面,由a数组元素衍生S中元素
- x=2y+1
转变成位运算就是左移一位末尾加一
- x=4y
转变成位运算就是左移两位
思路
找a中每个数的根源————往下找
#include<bits/stdc++.h> using namespace std; typedef long long ll; #define endl "\n" const int N = 2e5; const int MOD = 1e9 + 7; ll f[N + 1]; int main() { ios::sync_with_stdio(false), cin.tie(0), cout.tie(0); int n, p; cin >> n >> p; vector<ll>a(n + 1); for (int i = 1; i <= n; i++)cin >> a[i]; map<ll, bool>vis; f[1] = 1; f[0] = 0; f[2] = 2; for (int i = 3; i <= N; i++) { f[i] = (f[i - 1] + f[i - 2])%MOD; } for (int i = 1; i <= N; i++)f[i] = (f[i - 1] + f[i]) % MOD; sort(a.begin() + 1, a.end()); ll ans = 0; for (int i = 1; i <= n; i++) { ll t = a[i]; bool ok = true; while (t) { if (vis[t])ok = false; if (t & 1)t >>= 1; else if (t % 4 == 0)t >>= 2; else break; } if (!ok)continue; ll len = (ll)log2(a[i]) + 1LL; if(p>=len) ans =(ans+ f[max(0LL, (ll)p - len)]+1)%MOD; vis[a[i]] = true; } cout << ans << endl; return 0; }