翻译:
给定一个数组𝑎,该数组由𝑛个不同的正整数组成。
让我们考虑一个无限整数集𝑆,它包含至少满足以下条件之一的所有整数𝑥:
对于某些1≤𝑖≤𝑛,𝑥=𝑎𝑖。
𝑥=2𝑦+1,𝑦在𝑆中。
𝑥=4𝑦,𝑦在𝑆中。
例如,如果𝑎=[1,2],那么𝑆中最小的10个元素将是{1,2,3,4,5,7,8,9,11,12}。
找出𝑆中严格小于2𝑝的元素数量。由于这个数字可能太大,对109+7取模打印。
输入
第一行包含两个整数𝑛和𝑝(1≤𝑛,𝑝≤2⋅105)。
第二行包含𝑛整数𝑎1𝑎2,…,𝑎𝑛(1≤𝑎𝑖≤109)。
可以保证𝑎中的所有数字是不同的。
输出
打印一个整数,即𝑆中严格小于2𝑝的元素数量。记得对109+7取模打印。
例子
inputCopy
2 4
6个1
outputCopy
9
inputCopy
4个7
20 39 5 200
outputCopy
14
inputCopy
2 200000年
48763 1000000000
outputCopy
448201910
请注意
在第一个例子中,小于2^4的元素是{1,3,4,6,7,9,12,13,15}。
在第二个例子中,小于2^7的元素是{5,11,20,23,39,41,44,47,79,80,83,89,92,95}。
思路:
给的小于范围是的是2的幂次方的形式,然后每次变化是2x+1,或者4x,这就很有趣了,我们一可以将给的数组中的数字,转化成2的幂次方,向下取整,每次变换次方+1或者+2,这就变成了类似于经典上楼梯的问题,但是可以会有重复的。这样的话,小的值就会到达大的值,这样的话,如果都计入其对结果的贡献,就会出现有重复的部分,所以我们用map标记去重,然后记录每个的变换次数,类似于可以上多少次台阶,因为每次都是从本身开始遍历,所以相对应的就是从头开始上楼梯。可以仔细想一下,这个写法感觉非常巧妙!!
代码:
#include <iostream>
#include <algorithm>
#include <string.h>
#include <string>
#include <math.h>
#include <stdio.h>
#include<vector>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<tuple>
#include<numeric>
#include <unordered_map>
using namespace::std;
typedef long long ll;
inline __int128 read(){
__int128 x = 0, f = 1;
char ch = getchar();
while(ch < '0' || ch > '9'){
if(ch == '-')
f = -1;
ch = getchar();
}
while(ch >= '0' && ch <= '9'){
x = x * 10 + ch - '0';
ch = getchar();
}
return x * f;
}
inline void print(__int128 x){
if(x < 0){
putchar('-');
x = -x;
}
if(x > 9)
print(x / 10);
putchar(x % 10 + '0');
}
int n,p;
ll dp[200005];
ll ss;
ll mod=1e9+7;
ll ff[200005];
ll a[200005];
map<int, int>now;
int main(){
ios::sync_with_stdio(false);
cin.tie(); cout.tie();
cin>>n>>p;
int kl=1e6;
vector<int>we;
for (int i =1; i<=n; i++) {
cin>>a[i];
}
sort(a+1, a+1+n);
for (int i=1; i<=n; i++) {
ll st=a[i];
int bj=0;
while (1) {
if (st==0) {
break;
}
if ((st-1)%2==0) {
st-=1;
st/=2;
}
else if(st%4==0){
st/=4;
}
else{
break;
}
if (now.count(st)) {
bj=1;break;
}
}
if (bj) {
continue;
}
now[a[i]]=1;
int jk=0;
while (a[i]>0) {
a[i]/=2;
jk++;
}
we.push_back(jk);
};
ll na=0;
dp[1]=1;dp[2]=1;
for (int i =3; i<=p; i++) {
dp[i]=(dp[i-1]+dp[i-2])%mod;
}
for (int i =1; i<=p; i++) {
ff[i]=(ff[i-1]+dp[i])%mod;
}
for(auto x:we){
// printf("%d ",x);
if (x>p) {
continue;
}
na=(na+ff[p-x+1])%mod;
// printf("%lld\n",na);
}
printf("%lld\n",na);
return 0;
}