zl程序教程

您现在的位置是:首页 >  其他

当前栏目

位运算+线性dp

2023-04-18 15:35:15 时间

题目链接

Problem - D - Codeforces

由范围是2的p次方(p<2*10^5)
范围太大了
往位运算方面想

a数组集合都在S集合里面,由a数组元素衍生S中元素

  1. x=2y+1

转变成位运算就是左移一位末尾加一

  1. x=4y

转变成位运算就是左移两位

思路

找a中每个数的根源————往下找

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define endl "
"
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;
}