【解题报告】随便练练一(CF 2300)

A:The Child and Sequence | CF438D

题意

  • 长度为 n n n 的序列 a n a_n an,你需要实现如下共 m m m 次操作:
    (1)求区间和
    (2)区间取模 x x x
    (3)单点置 a k = x a_k=x ak=x
  • 1 ≤ n , m ≤ 1 0 5 1\le n,m\le 10^5 1n,m105
    1 ≤ a i ≤ 1 0 9 1\le a_i\le 10^9 1ai109

思路

  • 关键是区间取模怎么做,貌似是一个挺经典的题了。
    考虑,对于一个数 x x x,每次取模,这个数字最大变为 x 2 \frac{x}{2} 2x,所以最多取模次数是 O ( log ⁡ ) O(\log ) O(log) 级别的
  • 如果区间的最大值 m x < x mx<x mx<x,那么区间取模 x x x 相当于没有取模。
    如上两个操作就可以保证复杂度。注意我们只有单点置没有区间置。

代码

  • 时间复杂度: O ( ( n + m ) log ⁡ R ) O((n+m)\log R) O((n+m)logR)
#include<bits/stdc++.h>
using namespace std;
#define ls (p<<1)
#define rs (p<<1|1)
#define md ((l+r)>>1)
#define ll long long
const int MAX = 1e5+50;
ll aa[MAX];
ll treeSum[MAX*4];
ll treeMx[MAX*4];
void push_up(int p){
    treeSum[p]=treeSum[ls]+treeSum[rs];
    treeMx[p]=max(treeMx[ls],treeMx[rs]);
}
void build(int p,int l,int r){
    if(l == r){
        treeSum[p] = treeMx[p] = aa[l];
        return;
    }
    build(ls,l,md);
    build(rs,md+1,r);
    push_up(p);
}
void update(int p,int l,int r,int u,ll k){
    if(l == r){
        treeSum[p] = treeMx[p] = k;
        return;
    }
    if(u <= md)update(ls,l,md,u,k);
    if(u >  md)update(rs,md+1,r,u,k);
    push_up(p);
}
void update2(int p,int l,int r,int ux,int uy,ll k){
    if(treeMx[p] < k)return;
    if(l == r){
        treeSum[p] %= k;
        treeMx[p]  %= k;
        return;
    }
    if(ux <= md)update2(ls,l,md,ux,uy,k);
    if(uy >  md)update2(rs,md+1,r,ux,uy,k);
    push_up(p);
}
ll query(int p,int l,int r,int qx,int qy){
    ll res = 0;
    if(qx <= l && r <= qy)return treeSum[p];
    if(qx <= md)res += query(ls,l,md,qx,qy);
    if(qy >  md)res += query(rs,md+1,r,qx,qy);
    return res;
}
int main()
{
    int n,m;scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;++i)scanf("%lld",&aa[i]);
    build(1,1,n);
    for(int i = 1;i <= m;++i){
        ll op,t1,t2,t3;
        scanf("%lld",&op);
        if(op == 1){
            scanf("%lld%lld",&t1,&t2);
            printf("%lld\n",query(1,1,n,t1,t2));
        }else if(op == 2){
            scanf("%lld%lld%lld",&t1,&t2,&t3);
            update2(1,1,n,t1,t2,t3);
        }else{
            scanf("%lld%lld",&t1,&t2);
            update(1,1,n,t1,t2);
        }
    }
    return 0;
}

B:Errich-Tac-Toe (Hard Version) | CF1450C2

题意

  • 给定一个大小为 n × n n\times n n×n 的网格,每个格子要么为空,要么为 X X X,要么为 O O O
    规定,出现赢局就是行 / 列上有同时有三个相同的 O O O 或者 X X X
    在这里插入图片描述
  • 一次操作,你可以翻转一个 X X X 变成 O O O 或者翻转一个 O O O 变成 X X X
    假设棋盘上有 k k k 个棋子,请在最多 ⌊ k 3 ⌋ \lfloor \frac{k}{3}\rfloor 3k 步内让棋局没有赢局。
    1 ≤ n ≤ 300 1\le n\le 300 1n300
  • 你需要输出最后的没有赢局的局面。

思路

  • 感觉如果用各种奇妙的贪心和特判的话,这题会变得特别不好做。
    我们先考虑一下,如果一个局面全是 X X X 的话,怎么处理?

XXXXX
XXXXX
XXXXX
XXXXX
XXXXX

  |
  V

XXOXX
XOXXO
OXXOX
XXOXX
XOXXO

  • 可以依稀感觉到,对于 a x , y a_{x,y} ax,y 的棋子,我们按 ( x + y ) % 3 (x+y)\%3 (x+y)%3 作为三个同余类 S 0 , S 1 , S 2 S_0,S_1,S_2 S0,S1,S2去处理。
    如果我们定 S 0 S_0 S0 必须为 X X X,这样就可以保证不会有 O O O 的赢局
    如果我们定 S 0 S_0 S0 必须为 O O O,这样就可以保证不会有 X X X 的赢局
    我们不希望有 O O O X X X 的赢局,我们可以让 S 0 , S 1 , S 2 S_0,S_1,S_2 S0,S1,S2 中的两项取出来,满足上述俩要求即可。
  • 接下来是操作上限的证明
    容易得到:
    S 0 ( X ) + S 1 ( X ) + S 2 ( X ) + S 0 ( O ) + S 1 ( O ) + S 2 ( O ) = k S_0(X)+S_1(X)+S_2(X)+S_0(O)+S_1(O)+S_2(O)=k S0(X)+S1(X)+S2(X)+S0(O)+S1(O)+S2(O)=k
    所以必定存在一对 S t ( X ) , S t + 1 ( O ) S_t(X),S_{t+1}(O) St(X),St+1(O),满足
    S t ( X ) + S t + 1 ( O ) ≤ ⌊ k 3 ⌋ S_t(X)+S_{t+1}(O)\le \lfloor \frac{k}{3} \rfloor St(X)+St+1(O)3k
    当然也存在 S t ( O ) , S t + 1 ( X ) S_t(O),S_{t+1}(X) St(O),St+1(X) 也是满足的。

代码

  • 时间复杂度: O ( n 2 ) O(n^2) O(n2)
#include<bits/stdc++.h>
using namespace std;
void show(){std::cerr << endl;}template<typename T,typename... Args>void show(T x,Args... args){std::cerr << "[ " << x <<  " ] , ";show(args...);}
#define ll long long
const int MAX = 3e2+50;

char aa[MAX][MAX];

int main()
{
    int T;scanf("%d",&T);
    while(T--){
        int n;scanf("%d",&n);
        int k = 0;
        for(int i = 1;i <= n;++i)scanf("%s",aa[i]+1);

        for(int i = 1;i <= n;++i)
        for(int j = 1;j <= n;++j)
            if(aa[i][j] != '.')k++;

        for(int t = 0;t < 3;++t){
            int cnt = 0;
            for(int i = 1;i <= n;++i)
            for(int j = 1;j <= n;++j){
                if((i+j)%3 == t && aa[i][j] == 'X')cnt++;
                if((i+j+1)%3 == t && aa[i][j] == 'O')cnt++;
            }
            if(cnt <= k / 3){
                for(int i = 1;i <= n;++i){
                    for(int j = 1;j <= n;++j){
                        if((i+j)%3 == t && aa[i][j] == 'X')aa[i][j] = 'O';
                        if((i+j+1)%3 == t && aa[i][j] == 'O')aa[i][j] = 'X';
                        printf("%c",aa[i][j]);
                    }
                    puts("");
                }
                break;
            }
        }
    }
    return 0;
}

C:Sonya and Problem Wihtout a Legend | CF713C

题意(在原题上增强)

思路

  • 这个题目一个是改为单调不递减,一个是改为严格单调递增,但其实是等价的。
    假设原数列元素有 a < b < c a<b<c a<b<c
    我们令 a a ≤ b b ≤ c c aa\le bb\le cc aabbcc
    其实就是相当于 a a < b b − 1 < c c − 2 aa<bb-1<cc-2 aa<bb1<cc2
    也相当于 a a − 1 < b b − 2 < c c − 3 aa-1<bb-2<cc-3 aa1<bb2<cc3
    所以,我们原序列中的元素 a i a_i ai 更新为 a i = a i − i a_i=a_i-i ai=aii,那么严格单调递增问题就可以转化为单调不递减序列问题。
    注意到,我们问题之和 a i a_i ai a j a_j aj 的差值有关,而与 a i a_i ai 的具体数值是无关的,因此可以转化。
  • 有一个比较简单的例子。假设 n = 2 n=2 n=2,有数字 a , b a,b a,b,其中 a > b a>b a>b
    这个时候,答案一定是 b − a b-a ba,方案也很简单,就是 c ∈ [ a , b ] c\in[a,b] c[a,b],然后让 a , b a,b a,b 都变成 c c c 即可。
    注意到,如果数列长度比较长,为了让答案不劣,我们令 c = a c=a c=a 明显是更优的。
  • 假设现在我们处理到 i i i 的答案了,其中 a i − 1 a_{i-1} ai1 我们修改值变为了 a i − 1 ′ a_{i-1}^\prime ai1
    如果 a i ≥ a i − 1 ′ a_i\ge a_{i-1}^\prime aiai1,显然我们不需要修改。
    否则,我们需要多操作 a i − 1 ′ − a i a_{i-1}^\prime-a_i ai1ai 次操作。
    ∗ \color{red}{*} 在形式上,我们可以令 a i − 1 ′ = a i a_{i-1}^\prime=a_{i} ai1=ai,就像上面的让答案更优。但是可能会使得 a i − 1 ′ < a i − 2 ′ a_{i-1}^\prime<a_{i-2}^\prime ai1<ai2,但这并不妨碍我们,因为若我们令 a i ′ = a i − 1 ′ a_i^\prime=a_{i-1}^\prime ai=ai1,也是多操作了这些步骤,且保证一定是合法的。若 a i − 1 ′ < a i − 2 ′ a_{i-1}^\prime<a_{i-2}^\prime ai1<ai2 成立了,我们变 假装 调整这个序列,通过如下的手段:
1 3 3 3 5 (2) 新加入了 2
因为 2 < 5 ,我们要多操作 5-2=3 次
我们假装变成这样:
1 3 3 55)
在形式上,我们变成这样:
1 3 3 3 (2) 2
但是我们注意到了, 3 > 2,这个序列并不是单递增了
但是我们最后两个 2 可以随便转变为 [2,5] 中的随意数字,都是可以的,我们不妨把这两个点缩成一个点
1 3 3 3 (2)
然后我们再新加进来一个 1
1 3 3 3 2 (1)
注意到,此时序列中最高值为 3 ,我们要多操作 3-1=2 次
同理,序列中最左边的那个 3 和新加进来的 1 ,可以合并成一个点,且取值 [1,3] 都是可以的,我们自然取 1 最优
所以序列新变成了:
1 (1) 3 3 2
注意,这里我们都是假装的序列。如果要求是合法的序列,我们必须取值范围要取得更劣些,就变成这样:
1 [3] 3 3 (3 3) [3]
  • 从代码实现来说,就是用一个优先队列。最大元素为 x x x,现在新加进来一个 y y y
    如果 x ≤ y x\le y xy,我们自然不需要修改,把 y y y 丢进去即可。
    否则,我们需要多 x − y x-y xy 次操作,然后把 x x x 丢掉,再把 y y y 丢进去(点合并)
  • CF713C 标准题解是 O ( n 2 ) O(n^2) O(n2) 的离散化 d p dp dp,在评论区有人第一次表述了 O ( n log ⁡ n ) O(n\log n) O(nlogn) 的代码,但是是使用斜率和凸包分析描述的,不是很懂,但代码是相同的,这里提出自己的思考(瞎掰)。

代码

  • 时间复杂度: O ( n log ⁡ n ) O(n\log n) O(nlogn)
#include<bits/stdc++.h>
using namespace std;
void show(){std::cerr << endl;}template<typename T,typename... Args>void show(T x,Args... args){std::cerr << "[ " << x <<  " ] , ";show(args...);}
#define ll long long
const int MAX = 3e2+50;


priority_queue<int>Q;

int main()
{
    int n;scanf("%d",&n);
    ll ans = 0;
    for(int i = 1;i <= n;++i){
        int t;scanf("%d",&t);t -= i;
        Q.push(t);
        if(t < Q.top()){
            ans += Q.top() - t;
            Q.pop();
            Q.push(t);
        }
    }
    printf("%lld",ans);
    return 0;
}

D:Product Oriented Recurrence | CF1182E

题意

思路

  • 之前看有人牛客群里问了 f x = f x − 1 f x − 2 f_x=f_{x-1}f_{x-2} fx=fx1fx2 的问题咋做,随机就拉到了这题…
    一个很标准的矩阵快速幂的题目,会写的应该都会,稍微变变即可。
  • 第一步,我们记录每个数字 f x = f 1 a × f 2 b × f 3 c × o t h e r s f_x=f_1^{a}\times f_2^b\times f_3^c\times others fx=f1a×f2b×f3c×others,算出次数 a , b , c a,b,c a,b,c
    容易想到,对于乘积来说,次方是相加的。我们容易写出转移:
    ( 1 1 1 1 0 0 0 1 0 ) ( f n ( a ) f n ( b ) f n ( c ) f n − 1 ( a ) f n − 1 ( b ) f n − 1 ( c ) f n − 2 ( a ) f n − 2 ( b ) f n − 2 ( c ) ) = ( f n + 1 ( a ) f n + 1 ( b ) f n + 1 ( c ) f n ( a ) f n ( b ) f n ( c ) f n − 1 ( a ) f n − 1 ( b ) f n − 1 ( c ) ) \begin{pmatrix} 1&1&1\\ 1&0&0\\ 0&1&0\\ \end{pmatrix} \begin{pmatrix} f_n(a)&f_n(b)&f_n(c)\\ f_{n-1}(a)&f_{n-1}(b)&f_{n-1}(c)\\ f_{n-2}(a)&f_{n-2}(b)&f_{n-2}(c)\\ \end{pmatrix} = \begin{pmatrix} f_{n+1}(a)&f_{n+1}(b)&f_{n+1}(c)\\ f_n(a)&f_n(b)&f_n(c)\\ f_{n-1}(a)&f_{n-1}(b)&f_{n-1}(c)\\ \end{pmatrix} 110101100fn(a)fn1(a)fn2(a)fn(b)fn1(b)fn2(b)fn(c)fn1(c)fn2(c)=fn+1(a)fn(a)fn1(a)fn+1(b)fn(b)fn1(b)fn+1(c)fn(c)fn1(c)
    所以可以得出:
    ( 1 1 1 1 0 0 0 1 0 ) n − 3 ( 0 0 1 0 1 0 1 0 0 ) = ( f n ( a ) f n ( b ) f n ( c ) f n − 1 ( a ) f n − 1 ( b ) f n − 1 ( c ) f n − 2 ( a ) f n − 2 ( b ) f n − 2 ( c ) ) \begin{pmatrix} 1&1&1\\ 1&0&0\\ 0&1&0\\ \end{pmatrix}^{n-3} \begin{pmatrix} 0&0&1\\ 0&1&0\\ 1&0&0\\ \end{pmatrix} = \begin{pmatrix} f_n(a)&f_n(b)&f_n(c)\\ f_{n-1}(a)&f_{n-1}(b)&f_{n-1}(c)\\ f_{n-2}(a)&f_{n-2}(b)&f_{n-2}(c)\\ \end{pmatrix} 110101100n3001010100=fn(a)fn1(a)fn2(a)fn(b)fn1(b)fn2(b)fn(c)fn1(c)fn2(c)
  • 第二步,算出那个 f x = c d × o t h e r s f_x=c^d\times others fx=cd×others 底数为 c c c 的指数是多少,相同的道理,写出转移矩阵
    ( 1 1 1 1 1 − 2 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 1 ) × ( c i c i − 1 c i − 2 2 i 2 ) = ( c i + 1 c i c i − 1 2 ( i + 1 ) 2 ) \begin{pmatrix} 1&1&1&1&1&-2\\ 1&0&0&0&0&0\\ 0&1&0&0&0&0\\ 0&0&0&0&1&1\\ 0&0&0&0&0&1\\ \end{pmatrix} \times \begin{pmatrix} c_i\\ c_{i-1}\\ c_{i-2}\\ 2i\\ 2 \end{pmatrix} = \begin{pmatrix} c_{i+1}\\ c_{i}\\ c_{i-1}\\ 2(i+1)\\ 2 \end{pmatrix} 110001010010000100001001020011×cici1ci22i2=ci+1cici12(i+1)2
    所以我们有:
    ( 1 1 1 1 1 − 2 1 0 0 0 0 0 0 1 0 0 0 0 0 0 0 0 1 1 0 0 0 0 0 1 ) n − 4 × ( 14 6 2 12 2 ) = ( c n + 2 c n + 1 c n 2 ( n + 2 ) 2 ) \begin{pmatrix} 1&1&1&1&1&-2\\ 1&0&0&0&0&0\\ 0&1&0&0&0&0\\ 0&0&0&0&1&1\\ 0&0&0&0&0&1\\ \end{pmatrix}^{n-4} \times \begin{pmatrix} 14\\ 6\\ 2\\ 12\\ 2 \end{pmatrix} = \begin{pmatrix} c_{n+2}\\ c_{n+1}\\ c_{n}\\ 2(n+2)\\ 2 \end{pmatrix} 110001010010000100001001020011n4×1462122=cn+2cn+1cn2(n+2)2
  • 还有一点注意的,由于这里的数字都是指数,根据欧拉降幂,需要取模 φ ( P ) = P − 1 \varphi(P)=P-1 φ(P)=P1

代码

  • 时间复杂度: O ( s z 3 × log ⁡ n ) O(sz^3\times \log n) O(sz3×logn)
#include<bits/stdc++.h>
using namespace std;
void show(){std::cerr << endl;}template<typename T,typename... Args>void show(T x,Args... args){std::cerr << "[ " << x <<  " ] , ";show(args...);}
#define ll long long
const int MAX = 3e2+50;
const int MOD = 1e9+6;
const int MOD2 = 1e9+7;
typedef long long Elemtype;
const int SZ = 5;
struct Matrix{
    Elemtype mat[SZ][SZ];
}M1,M2,M3,M0;

Matrix mul(Matrix x,Matrix y,ll sz){
    Matrix ans;
    for(int i=0;i<sz;++i){
        for(int j=0;j<sz;++j){
            ans.mat[i][j]=0;
            for(int k=0;k<sz;++k){
                ans.mat[i][j]+=(x.mat[i][k]*y.mat[k][j])%MOD;
            }
            ans.mat[i][j]%=MOD;
        }
    }
    return ans;
}
ll qpow(ll a, ll n,ll pmod)
{
    ll ans = 1;
    while(n){
        if(n&1){
            ans=ans*a%pmod;
        }
        n>>=1;
        a=a*a%pmod;
    }
    return ans;
}
Matrix Create_Matrix(ll sz){
    Matrix ans;
    for(ll i=0;i<sz;++i)
        for(ll j=0;j<sz;++j)
            if(i==j)ans.mat[i][j]=1;
            else ans.mat[i][j]=0;
    return ans;
}
Matrix M_qpow(Matrix x,ll n,ll sz)
{
    Matrix ans = Create_Matrix(sz);
    while(n){
        if(n&1){
            ans = mul(ans,x,sz);
        }
        n>>=1;
        x = mul(x,x,sz);
    }
    return ans;
}

void show_M(Matrix x,int sz){
    puts("---");
    for(int i = 0;i < sz;++i){
        for(int j = 0;j < sz;++j){
            cout << x.mat[i][j] << " ";
        }
        puts("");
    }
    puts("---");
}

int main()
{
    ll n,a,b,c,d;
    ll ans = 0;
    cin >> n >> a >> b >> c >> d;

    M1.mat[0][0] = M1.mat[0][1] = M1.mat[0][2] = 1;
    M1.mat[1][0] = M1.mat[2][1] = 1;
    M1 = M_qpow(M1,n-3,3);

    M0.mat[0][2] = M0.mat[1][1] = M0.mat[2][0] = 1;

    M1 = mul(M1,M0,3);

    ans = qpow(a,M1.mat[0][0],MOD2) * qpow(b,M1.mat[0][1],MOD2) % MOD2 * qpow(c,M1.mat[0][2],MOD2) % MOD2;

    M2.mat[0][0] = M2.mat[0][1] = M2.mat[0][2] = M2.mat[0][3] = 1;
    M2.mat[0][4] = (-2 + MOD);
    M2.mat[1][0] = M2.mat[2][1] = M2.mat[3][3] = M2.mat[3][4] = M2.mat[4][4] = 1;
    M2 = M_qpow(M2,n-4,5);


    M3.mat[0][0] = 14;
    M3.mat[1][0] = 6;
    M3.mat[2][0] = 2;
    M3.mat[3][0] = 12;
    M3.mat[4][0] = 2;

    M3 = mul(M2,M3,5);


    ans = ans * qpow(d,M3.mat[2][0],MOD2) % MOD2;
    printf("%lld",ans);


    return 0;
}

E:Divisibility Rules | CF180B

题意

思路

  • 前置:
    ∗ \color{red}{*} x n − 1 = ( x − 1 ) ( x n − 1 + x n − 2 + ⋯ + 1 ) x^n-1=(x-1)(x^{n-1}+x^{n-2}+\cdots+1) xn1=(x1)(xn1+xn2++1)
    ∗ \color{red}{*} x n + 1 = ( x + 1 ) ( x n − 1 − x n − 2 + ⋯ + 1 ) x^n+1=(x+1)(x^{n-1}-x^{n-2}+\cdots+1) xn+1=(x+1)(xn1xn2++1) 其中 n n n 是奇数
  • 首先是最简单的 2 − t y p e 2-type 2type
    注意到,也就是我们希望满足 d × k = b x d\times k=b^x d×k=bx 对于最小的正整数 x x x 和一个正整数 k k k 成立。
    注意到,此时 d d d 的所有质因子都必须包含于 b b b 的所有质因子。
    代码实现上,若 gcd ⁡ ( d , b ) ≠ 1 \gcd(d,b)\ne 1 gcd(d,b)=1,则我们每次让 d = d / gcd ⁡ ( d , b ) d=d/\gcd(d,b) d=d/gcd(d,b),没除一次,则 x = x + 1 x=x+1 x=x+1
    此时若 d = 1 d=1 d=1,则就是 2 − t y p e 2-type 2type,此时的 x x x 就是最小的 x x x
  • 然后就是 3 , 11 , 6 − t y p e 3,11,6-type 3,11,6type
    3 − t y p e 3-type 3type,我们需要把 b b b 进制下的 d d d 写出来。
    d = ∑ i = 0 ∞ a i b i d=\sum_{i=0}^\infin a_ib^i d=i=0aibi
    注意到此时我们当然有
    ∑ i = 0 ∞ a i b i ≡ 0 ( m o d d ) \sum_{i=0}^\infin a_ib^i \equiv 0\pmod d i=0aibi0(modd)
    对于 3 − t y p e 3-type 3type,我们有
    ∑ i = 0 ∞ a i ≡ 0 ( m o d d ) \sum_{i=0}^\infin a_i \equiv 0\pmod d i=0ai0(modd)
    两式子合并,得到:
    ∑ i = 0 ∞ a i ( b i − 1 ) ≡ 0 ( m o d d ) ∑ i = 0 ∞ a i ( b − 1 ) ( o t h e r s ) ≡ 0 ( m o d d ) \sum_{i=0}^\infin a_i(b^i-1) \equiv 0\pmod d\\ \sum_{i=0}^\infin a_i(b-1)(others) \equiv 0\pmod d\\ i=0ai(bi1)0(modd)i=0ai(b1)(others)0(modd)
    也就是说 b − 1 b-1 b1 d d d 的倍数
  • 然后是 11 − t y p e 11-type 11type,同理
    ∑ i = 0 ∞ a i b i ≡ 0 ( m o d d ) ∑ i = 0 ∞ ( − 1 ) i + 1 a i ≡ 0 ( m o d d ) \sum_{i=0}^\infin a_ib^i \equiv 0\pmod d\\ \sum_{i=0}^\infin (-1)^{i+1}a_i\equiv 0\pmod d i=0aibi0(modd)i=0(1)i+1ai0(modd)
    得到以下式子:
    ∑ i = 0 ∞ a i ( b i + ( − 1 ) i + 1 ) ≡ 0 ( m o d d ) \sum_{i=0}^\infin a_i(b^i+(-1)^{i+1}) \equiv 0\pmod d\\ i=0ai(bi+(1)i+1)0(modd)
    i i i 是奇数,则会变成 b J + 1 = ( b + 1 ) ( O t h e r s ) b^J+1=(b+1)(Others) bJ+1=(b+1)(Others) 的形式
    i i i 是偶数,则会变成 b 2 x − 1 = ( b x + 1 ) ( b x − 1 ) b^{2x}-1=(b^x+1)(b^x-1) b2x1=(bx+1)(bx1) x x x 是奇数,那么左边这一项可以分出来一个 ( b + 1 ) ( O t h e r s ) (b+1)(Others) (b+1)(Others);若 x x x 是偶数,那么继续拆 b x − 1 b^x-1 bx1,就是一个递归问题了。
  • 所以此时一定有 1 + b 1+b 1+b d d d 的倍数
    注意,以上两种都要求 x = 0 x=0 x=0,也就是 gcd ⁡ ( b , d ) = 1 \gcd(b,d)=1 gcd(b,d)=1
    6 − t y p e 6-type 6type,也就是上述有两种同时满足,就是 b + 1 和 b − 1 b+1和 b-1 b+1b1 同时是 d d d 的倍数即可。
    ∗ \color{red}{*} 如果符合 3 − t y p e 3-type 3type 或者 11 − t y p e 11-type 11type,那么一定符合 2 − t y p e 2-type 2type
    否则就是 7 − t y p e 7-type 7type

代码

  • 时间复杂度: O ( log ⁡ R ) O(\log R) O(logR)
#include<bits/stdc++.h>
using namespace std;
void show(){std::cerr << endl;}template<typename T,typename... Args>void show(T x,Args... args){std::cerr << "[ " << x <<  " ] , ";show(args...);}
#define ll long long
const int MAX = 3e2+50;
const int MOD = 1e9+6;

int lcm(int x,int y){
    return x * y / __gcd(x,y);
}

int main()
{
    int b,d,dd,cnt = 0;
    cin >> b >> d;
    dd = d;
    while(__gcd(dd,b) > 1){
        dd /= __gcd(dd,b);
        cnt++;
    }
    if(dd == 1){
        puts("2-type");
        printf("%d",cnt);
    }else if(!(lcm(b-1,b+1) % dd)){
        if(!cnt && !((b-1) % dd))puts("3-type");
        else if(!cnt && !((b+1) % dd))puts("11-type");
        else puts("6-type");
    }else{
        puts("7-type");
    }
    return 0;
}

  • 4
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值