Codeforces Round #631 (Div. 2) D. Dreamoon Likes Sequences (bitmasks +dp )

https://codeforces.com/contest/1330/problem/D

题目大意:给出一个限制 d 与模数 m ,求出可以构造出的满足条件的数组 a 的个数,需要满足以下条件:
    1.数组 a 的长度大于等于 1
    2.数组 a 严格递增
    3.任意的ai <=d且>=1
    4.对于数组 a ,需要构造出一个数组 b :满足当 i == 1 时:b[ 1 ] = a[ 1 ], i > 1 时:b[ i ] = b[ i - 1 ] XOR a[ i ]  ,同时数组 b 严格递增

题目大致可以转化为:构造数组a,长度大于等于1,且其异或和单调递增。也就是说a1 <a1^a2 <a1^a2^a3....,这个性质可以得出结论:a3的二进制最高位和a2的二进制最高位不能处在同一位置上,否则异或前缀和必定不递增。

例如 2和3 二进制分别为10和11,若a2 = 2,a3 = 3,虽然满足a2 < a3,但是其XOR和必然不递增,同理4 5 6 7 这四个数字相互异或也必然不递增。

考虑最高位1的位置:若最高位1处在第一位,显然只存在 1

                                  若最高位1处在第二位,存在2 、3

                                  若最高位1处在第三位,存在4,5,6,7

                                  若最高位1处在第四位,存在8,9,10,11,12,13,14,15

现在可以组合数组a了。例如 当ai 取了2或3,那么ai+1只能从4 5 6 7 或者 8 9 10 11 12 13 14 15或者更靠后的数字中取,依次类推这样就可以轻易设计dp状态了。

dp[i] 表示二进制最高位1在前第 i 位的方案数之和,则dp[i] = dp[i - i] * cnt[i] + dp[i-1] + cnt[i] (cnt[i]表示最高位是i的数字个数,若只单独取cnt[i]也可以满足题意)

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long ll;
 4 const int maxn = 1e5 + 5;
 5 ll dp[32],cnt[32];
 6 int main() {
 7     int t;
 8     cin>>t;
 9     while(t--){
10         ll d,m;
11         cin>>d>>m;
12         memset(dp,0,sizeof(dp));
13         memset(cnt,0,sizeof(cnt));
14         ll cal = d,cur = 1,indx = 1;
15         while(cal){
16             cnt[indx++] = min(d - (cur - 1), cur);
17             cal>>=1;
18             cur<<=1;
19         }
20     //    cout<<indx<<endl;
21         for(int i = 1;i<indx;i++){
22             dp[i] = (dp[i-1]*cnt[i]%m + cnt[i]%m + dp[i-1])%m;
23         }
24         cout<<dp[indx-1]<<endl;
25     }
26     return 0;
27 }
原文地址:https://www.cnblogs.com/AaronChang/p/12635428.html