Codeforces Round #631 (Div. 1) B. Dreamoon Likes Sequences 题解(思维+求贡献)

题目链接

题目大意

让你构造一个严格单调上升的数组a满足\(1<=a_1<a_2<....a_n<=d\)

而且要使得这个数组的异或前缀和也满足严格单调上升,求有多少个满足条件的数组(mod m)

题目思路

首先这个数组的性质很容易观察就是后一个数化为二进制的最高位1要比第上一个高

然后我就不会了

我还以为是枚举数组长度啥的,果然是我太菜了

这种类型的题目需要求贡献。枚举位数为 i 的数是否在序列中出现并计算对答案的贡献,根据乘法原理相乘即答案。

当位数小于log(d)的位数,贡献则为\(2^i+1\)(位数为i的个数或不出现)

还要注意减去n=0的情况

代码

#include<set>
#include<map>
#include<queue>
#include<stack>
#include<cmath>
#include<cstdio>
#include<vector>
#include<string>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<unordered_map>
#define fi first
#define se second
#define debug printf(" I am here\n");
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> pii;
const ll INF=0x3f3f3f3f3f3f3f3f;
const int maxn=2e5+5,inf=0x3f3f3f3f,mod=1e9+7;
const double eps=1e-10;
int d,m;
signed main(){
    int _;scanf("%d",&_);
    while(_--){
        scanf("%d%d",&d,&m);
        ll ans=1;
        for(int i=0;(1<<i)<=d;i++){
            ans=ans*(min((1<<i)+1,d-((1<<i)-1)+1))%m;
            //可以选(1<<i)或者不选+1
        }
        ans=(ans-1+m)%m;//数列不能为0
        printf("%lld\n",ans);
    }
    return 0;
}

posted @ 2020-09-30 16:55  hunxuewangzi  阅读(79)  评论(0编辑  收藏  举报