Codeforces 1330D. Dreamoon Likes Sequences(思维 + 递推) /详解

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。

思路:

  1. 这题是比赛时没写出来的,也没搞懂,今天逛了一圈,也没发现什么人写的比较详细,所以就打算写一下这篇博客,算是让自己梳理一下思路。
  2. 首先,因为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数列就不是递增的了。
  3. 所以考虑取二进制第i位的话:有全0~全1的范围 即2i+12^{(i+1)}-1种方案,要减去会消掉当前第i-1位1的方案即 2i2^{i}-1 ;
  4. 而考虑不取这第i位的话,就跳到下一位,但这也是一种方法,比如说给你的d是9: 假设每个位都取得话可以是:1 2 4 8 但是其中得某一位并不是一定要取的,例如1 2 8也是一种答案,所以不取的方案也要算到这一二进制位的贡献上去,所以总的贡献即:
  5. 2i+12^{(i+1)}-1 )-( 2i2^{i}-1 )+1
  6. 可化简为:2i+12^{(i+1)} - 2i2^{i} +1
  7. 最后注意的一点是当枚举的二进制位趋向于d时,会出现能取的范围并没有 0~全1,这个时候就要取min( d ,2i+12^{(i+1)}-1)。
  8. 所以枚举每个二进制位,把方案数累积起来,最后减去全0的方案,就是最后求的答案。
  9. 如果觉得有帮助的话给个赞,谢谢!
  10. 或者有什么讲的不清楚的欢迎留言私信交流~

代码:

#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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章