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 }