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;
}