D. Dreamoon Likes Sequences
题意:
给你d和m,让你构造一个递增数组a,使数组b(i==1,b[i]=a[i] ; i>1, b[i]=b[i-1]^a[i])递增,求a有几种,答案模m。
思路:
- 这题是比赛时没写出来的,也没搞懂,今天逛了一圈,也没发现什么人写的比较详细,所以就打算写一下这篇博客,算是让自己梳理一下思路。
- 首先,因为b数列的生成是b[i-1] xor a[i] ,所以如果a[i-1]在第i-1位选了1的话,那么a[i]在第i位必须选1,即b[i]必须是递增的,例如,a[i-1]=2,那么a[i]必须是4,如果是3的话,那么b[i]=b[i-1]^a[i],就会把第i位的1给消去,那么此时b数列就不是递增的了。
- 所以考虑取二进制第i位的话:有全0~全1的范围 即-1种方案,要减去会消掉当前第i-1位1的方案即 -1 ;
- 而考虑不取这第i位的话,就跳到下一位,但这也是一种方法,比如说给你的d是9: 假设每个位都取得话可以是:1 2 4 8 但是其中得某一位并不是一定要取的,例如1 2 8也是一种答案,所以不取的方案也要算到这一二进制位的贡献上去,所以总的贡献即:
- ( -1 )-( -1 )+1
- 可化简为: - +1
- 最后注意的一点是当枚举的二进制位趋向于d时,会出现能取的范围并没有 0~全1,这个时候就要取min( d ,-1)。
- 所以枚举每个二进制位,把方案数累积起来,最后减去全0的方案,就是最后求的答案。
- 如果觉得有帮助的话给个赞,谢谢!
- 或者有什么讲的不清楚的欢迎留言私信交流~
代码:
#include<bits/stdc++.h>
#define ll long long
#define ull unsigned long long
#define inf 0x3f3f3f3f
#define mod 1000000007
#define pb push_back
#define lowbit(x) (x&(-x))
using namespace std;
inline ll read(){ll s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();return s*w;}
void put1(){ puts("Yes") ;}void put2(){ puts("No") ;}void put3(){ puts("-1"); }
ll qp(ll a,ll b, ll p){ll ans = 1;while(b){if(b&1){ans = (ans*a)%p;--b;}a =
(a*a)%p;b >>= 1;}return ans%p;}
const ull base=2333; const ull pp=19260811; const ull ppp=999998639;
const int manx=5e5+5;
const int mo=998244353;
ll dp[manx];
int main(){
ll p=read();
while(p--){
ll d=read(),m=read();
ll ans=1;
for(int i=0;i<30;i++){
ll x= (1<<i) ;
if(d < x) break;
ans = ans * (min((x<<1)-1ll,d) - x +1 +1) % m;
}
ans = (ans -1 +m) %m;
printf("%lld\n",ans);
}
return 0;
}