Codeforces Round #632 (Div. 2) D. Dreamoon Likes Sequences (思维 + 乘法原理)

Posted lasomisolaso~

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #632 (Div. 2) D. Dreamoon Likes Sequences (思维 + 乘法原理)相关的知识,希望对你有一定的参考价值。

思维+乘法原理

题意:

给出一个上限 d d d,和一个模数 m m m,计算符合下列条件的数列 a a a的个数:

  1. 数列 a a a的长度大于等于 1 1 1
  2. 数列 a a a的最小值大于等于 1 1 1,最大值小于等于 d d d,且是严格单调递增的。
  3. 对于 a a a用如下方式构造一个数列 b b b, 要求构造的数列 b b b是严格单调递增的。
    b 1 = a 1 b_1 = a_1 b1=a1
    b i = b i − 1 ⨁ a i ( i ≥ 1 ) b_i = b_i -1 \\bigoplus a_i (i \\geq 1) bi=bi1ai(i1)

题解:

参考官方题解:
首先定义一个函数 h ( a i ) h(a_i) h(ai),表示 a i a_i ai的二进制表示中数位为1的最高位是哪一位。比如 h ( 10 ) = 3 h(10) = 3 h(10)=3。由a是严格单调递增的条件我们可以知道, h ( a i + 1 ) > = h ( a i ) h(a_i+1) >= h(a_i) h(ai+1)>=h(ai)
然后我们利用b是严格单调递增的条件, b 2 = a 1 ⨁ a 2 , b 2 > b 1 b_2 = a_1 \\bigoplus a_2, b_2 > b_1 b2=a1a2,b2>b1。可以知道 h ( a 2 ) > h ( a 1 ) h(a_2) > h(a_1) h(a2)>h(a1),如果 h ( a 2 ) = h ( a 1 ) h(a_2) = h(a_1) h(a2)=h(a1)的话,那么异或之后这个最高位将会变成0,导致 b 2 < b 1 b_2 < b_1 b2<b1
同时我们也可以得出 h ( b 2 ) = h ( a 2 ) h(b_2) = h(a_2) h(b2)=h(a2)。依次类推就可以得出 h ( b i ) = h ( a i ) , h ( a i + 1 ) > h ( a i ) h(b_i) = h(a_i), h(a_i+1) > h(a_i) h(bi)=h(ai),h(ai+1)>h(ai)

每一个 h ( a i ) h(a_i) h(ai)都是不同的,且是严格递增的。那么在符合条件的数列中,只有一个 a i a_i ai或者没有 a i a_i ai满足 h ( a i ) = v h(a_i) = v h(ai)=v。也就是只有一个或者没有 a i a_i ai属于 [ 2 v , m i n ( 2 v + 1 − 1 , d ) ] [2^v, min(2^v +1 - 1, d)] [2v,min(2v+11,d)]。只要从每一个数段中选出一个数,或者不选,这样组成的数列从小到大排序都是合法的。每一段有 m i n ( 2 v + 1 − 1 , d ) − 2 v + 2 min(2^v+1 - 1, d) - 2^v+2 min(2v+11,d)2v+2个选择。根据乘法原理就可求出总数,最后要减去每一个都不选形成的数列。

代码:

/**
* Author : Xiuchen
* Date : 2020-04-07-12.02.25
* Description : 乘法原理
*/
#pragma GCC optimize(1)
#pragma GCC optimize(2)
#pragma GCC optimize(3,"Ofast","inline")
#include<cstdio>
#include<cstring>
#include<string>
#include<vector>
#include<stack>
#include<queue>
#include<map>
#include<cmath>
#include<math.h>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3fLL;
//const int maxn = ;
int gcd(int a, int b)
    return b ? gcd(b, a % b) : a;

int t;
ll d, m;
int main()
    cin >> t;
    while(t--)
        cin >> d >> m;
        ll ans = 1 % m;
        for(int i = 0; i <= 31; i++)
            ll tmp = 1 << i;
            if(tmp > d) break;
            ll num = min((1ll << (i + 1)) - 1, d) - tmp + 2;
            ans = ans * num % m;
        
        cout << (ans - 1 + m) % m << endl;
    
    return 0;


以上是关于Codeforces Round #632 (Div. 2) D. Dreamoon Likes Sequences (思维 + 乘法原理)的主要内容,如果未能解决你的问题,请参考以下文章

[每日一题]:Codeforces Round #632 (Div. 2) C. Eugene and an array

Codeforces Round #632 (Div. 2) D. Dreamoon Likes Sequences (思维 + 乘法原理)

Codeforces Round #632 (Div. 2)F. Kate and imperfection(逆向贪心因子)

Codeforces Round #632 (Div. 2)F. Kate and imperfection(逆向贪心因子)

Codeforces Round #436 E. Fire(背包dp+输出路径)

[ACM]Codeforces Round #534 (Div. 2)