牛客多校2025 R6

ouyu69 发布于 2025-08-16 40 次阅读


B Base Conversion Master

 

题目大意

有一个初始 , 目标结果,还有 个数组 (每一个数组的第一个元素一定不是 ) , 从第一数组依次往下看下一个数组,对于第一个数组,我们把它的表现形式看作 进制的形式 , 假设 ,进而算出实际值为 ,让 , 接着我们把第二个数组看作 进制形式,依次类推一直算到最后一个数,得到 ,问当 的取值范围 分别取什么值时才能使

思路

我们很容易发现如果 个数组中不存在长度为 的数组,呢么 是单调不减的,并且 越大也就可以越让计算的数组满足进制形式,也就是数组的每一个元素都小于当前进制形式,因此我们就可以直接二分我们的初始取值范围的 (注意计算新的 时,数据会很大,但实际上这个值只会和 比较,所以说在计算过程中如果只要出现大于 ,那么最后结果一定也是大于 的)。

对于出现长度为 的数组的情况,因为 此时 不会对这个数组计算来的进制数造成影响,也就影响了 的单调性,先要找到最后一个长度为 的数组的位置,因为这个位置确定了最后 的结果,如果计算结果不是 ,那么一定不合法,反之我们二分左边界即可。

代码
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define endl '\n'
#define PII pair<int,int>
#define F first 
#define S second 
#define int long long
#define i128 __int128_t
#define all(vec) vec.begin(),vec.end()  
#define vi vector<int>   
#define vii vector<vector<int>>   
using namespace std;
const int N = 5e5+10 ;
const int M = 1e3+10 ;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int MOD1 = 1e9 + 7 ;
const int MOD2 = 998244353 ;
const double eps = 1e-9 ;
int gcd(int a, int b){ return b == 0 ? a : gcd(b, a%b); }
int lcm(int a, int b){ return a * b / gcd(a,b); } 
int _ = 1 ;
int ans = 0 ;
int n , m, k, q, y ;
int qmi(int a, int b){
    int res = 1 ;
    while(b){
        if(b&1){
            if( a > 1e9 || res * a > 1e9) return 1e9 + 10 ;
            res = res * a ;
        }
        b >>= 1 ;
        a = a * a ;

    }
    return res ;
}
void solve(){
    cin >> n >> y >> m ;
    vii a(n) ;
    int len, x ;
    int me = -1 ;
    for(int i = 0 ; i < n ; ++ i){
        cin >> len ;
        if(len == 1){
            me = i ;
        }
        for(int j = 0 ; j < len ; ++ j){
            cin >> x ;
            a[i].push_back(x) ;
        }
    }
    if(me != -1){// 说明无论初始如何选一定会从 me 的 值开始
        int s =   a[me][0] ;
        int la = 0 ;
        for(int i = me + 1 ; i < n ; ++ i){
            la = s ;
            s = 0 ;
            for(int j = 0 ; j < a[i].size() ; ++ j){
                if(a[i][j] >= la){
                    cout << -1 << " " << -1 << endl ;
                    return ;
                }
                s = min(s * la + a[i][j],1000000010LL);
            }
        }
        if(s == y){//但是要保证之前的位置都是合法的
            int l = 2 , r = m ;
            int l1 = m + 1 ;
            auto check3 = [&](int x) -> bool {// s 越大月能满足
                int s = 0 ;
                int la = x ;
                for(int i = 0 ; i <= me ; ++ i){
                    for(int j = 0 ; j < a[i].size() ; ++ j ){
                        if(a[i][j] >= la ) return false ;
                        s = min(s * la + a[i][j],1000000010LL);
                    }
                    la = s ;
                    s = 0 ;
                }
                return true ;
            };
            while(l <= r){
                int mid = l + r >> 1 ;
                if(check3(mid)){
                    l1 = mid ;
                    r = mid -1 ;
                }else{
                    l = mid + 1 ;
                }
            }
            if(l1<=m){
                cout << l1 << " " << m << endl ;
            }else{
                cout << -1 << " " << -1 << endl ;
            }
        }else{
            cout << -1 << " " << -1 << endl ;
        }
        return ;
    }
    auto check1 = [&](int x) -> bool {// s 越大月能满足
        int s = 0 ;
        int la = x ;
        for(int i = 0 ; i <  n ; ++ i){
            for(int j = 0 ; j < a[i].size() ; ++ j ){
                if(a[i][j] >= la ) return false ;
                s = min(s * la + a[i][j],1000000010LL);
                if(s > y){
                    return true;
                }
            }
            la = s ;
            s = 0 ;
        }
        return la >= y ;
    };
    auto check2 = [&](int x) -> bool {
        int s = 0 ;
        int la = x ;
        for(int i = 0 ; i <  n ; ++ i){
            for(int j = 0 ; j < a[i].size() ; ++ j ){
                if(a[i][j] >= la ) return true ;
                s = min(s * la + a[i][j],1000000010LL);
                if(s > y){
                    return false;
                }
            }
            la = s ;
            s = 0 ;
        }
        return la <= y ;
    };
    int l1 = m + 1 ;
    int l = 2, r = m ;
    while(l <= r){
        int mid = l + r >> 1 ;
        if(check1(mid)){
            l1 =mid ; 
            r = mid - 1 ;
        }else{
            l = mid + 1 ;
        }
    }
    int r1 = 1 ;
    l = 2, r = m ;
    while(l <= r){
        int mid = l + r >> 1 ;
        if(check2(mid)){
            r1 = mid ; 
            l = mid + 1 ;
        }else{
            r = mid - 1 ;
        }
    }
    auto check4 = [&](int x) -> bool {
        int s = 0 ;
        int la = x ;
        for(int i = 0 ; i <  n ; ++ i){
            for(int j = 0 ; j < a[i].size() ; ++ j ){
                if(a[i][j] >= la ) return false ;
                s = min(s * la + a[i][j],1000000010LL);
                if(s > y){
                    return false;
                }
            }
            la = s ;
            s = 0 ;
        }
        return la == y ;
    };
    if(l1 > r1 || l1 > m || r1 < 2 || !check4(l1) || !check4(r1)){
        cout << -1 << " " << -1 << endl ;
        return ;
    }
    cout << l1 << " " << r1 << endl ;
}

signed main(){
    IOS ;
    cin >> _ ;
    while(_ --){
        solve() ;
    }
    return 0;
}

 


C Stack

题目大意

表示长度为 的一种排列, 表示对这个排列进行单调栈运算后的栈长度的,题目问所有的排列的 的和。

思路

我们设 吧,表示对于长度 的排列中单调栈长度为 的排列的数量,我们的转移可以看作向长度为的排列中项添加新元素 ,我们可以发现只有把 放到排列的最后一个位置才能让单调栈的长度增加 ,因此递推如下

第一项表示放在最后一个位置,第二项表示放在除最后一个位置的其个位置。

那么

表示长度为 的所有排列的单调栈的长度之和

变换得

变换得

变换得

综上

以此直接递推即可

代码
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define endl '\n'
#define double long double
#define PII pair<int,int>
#define F first 
#define S second 
#define int long long
#define i128 __int128_t
#define all(vec) vec.begin(),vec.end()  
#define vi vector<int>   
#define vii vector<vector<int>>   
using namespace std;
const int N = 5e5+10 ;
const int M = 1e3+10 ;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int MOD1 = 1e9 + 7 ;
const int MOD2 = 998244353 ;
const double eps = 1e-9 ;
int gcd(int a, int b){ return b == 0 ? a : gcd(b, a%b); }
int lcm(int a, int b){ return a * b / gcd(a,b); } 
int _ = 1 ;
int ans = 0 ;
int n , m, k, q ;
int qmi(int a, int b){
    int res = 1 ;
    while(b){
        if(b & 1) res = res * a % MOD2 ;
        b >>= 1  ;
        a = a * a % MOD2 ; 
    }
    return res ;
}
int f[N], g[N], h[N] ;
int fac[N] ;
void init(){
    fac[1] = 1;
    for(int i = 2 ; i< N ; ++ i){
        fac[i] = fac[i-1] * i % MOD2 ;
    }
    f[1] = 1 ;
    g[1] = 1 ;
    h[1] = 1 ;
    for(int i = 2; i < N ; ++ i){
        f[i] = (i * f[i-1] % MOD2 + fac[i-1]) % MOD2 ;
        g[i] = (i * g[i-1] % MOD2 + 2 * f[i-1] + fac[i-1]) % MOD2 ;
        h[i] = (((i * h[i-1] % MOD2 + 3 * g[i-1] % MOD2) % MOD2 + 3 * f[i-1] % MOD2) % MOD2 + fac[i-1]) % MOD2 ;
    }
}
void solve(){
    cin >> n ;
    cout << h[n] << endl ;
}

signed main(){
    IOS ;
    init() ;
    cin >> _ ;
    while(_ --){
        solve() ;
    }
    return 0;
}

 


D Beautiful Matrix

思路

因为

所以

我们设 ,实质就是 的每一行的差分,接着我们保证只要每一行的的 都为正数并且和 小于等于 就可以满足 这两个条件。我们的 矩阵就转化成了 矩阵,并且对于 的每一列从上到小单调不增。

我们假设 , 因为列上单调不增,我们可以看作对这一列的从下到上的差分的和等于 ,也就就可以看作把 分成 份,每一份可以为空集,这样就保证了满足 , 计算公式就是 ,也即是说 时,这一列的方案书就是

答案就是 中的前 项的系数之和

由广义牛顿二项式定理得

所以说

所以答案就是

#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define endl '\n'
#define PII pair<int,int>
#define F first 
#define S second 
#define int long long
#define i128 __int128_t
#define all(vec) vec.begin(),vec.end()  
#define vi vector<int>   
#define vii vector<vector<int>>   
using namespace std;
const int N = 5e5+10 ;
const int M = 1e3+10 ;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int MOD1 = 1e9 + 7 ;
const int MOD2 = 998244353 ;
const double eps = 1e-9 ;
int gcd(int a, int b){ return b == 0 ? a : gcd(b, a%b); }
int lcm(int a, int b){ return a * b / gcd(a,b); } 
int _ = 1 ;
int ans = 0 ;
int n , m, k, q, y ;
int qmi(int a, int b){
    int res = 1 ;
    while(b){
        if(b&1) res = res * a % MOD2 ;
        b >>= 1 ;
        a = a * a % MOD2;

    }
    return res ;
}
void solve(){
    ans =  0 ;
    cin >> n >> m ;
    int a1 = 1 , a2 = 1 ;
    for(int i = 1 ; i <= m ; ++ i){ 
        a1 = a1 * ((n * (n-1) + m - i + 1) % MOD2) % MOD2 ;
        a2 = a2 * i % MOD2 ;
    }
    ans = a1 * qmi(a2,MOD2 - 2) % MOD2 ;
    cout << ans << endl ;

}

signed main(){
    IOS ;
    while(_ --){
        solve() ;
    }
    return 0;
}

 


D Maximum GCD

题目大意

给定一个长度为 的数组, 你可以选择一个区间,让这个区间的数都增加 , 问你最大能使得这个数组的 为多大。

思路

当区间选择就是整个数组时,根据上式吗实质上就是 和后续差分的 ,我们一定能够让 变为后续差分 的倍数,此时答案就是后续差分的

当选择的区间不包含第一个数 时,我们可以发现最终的 一定是 的因子,因此我们枚举 的因子,然后我们查看数组的差分中有哪些位置上的数不是当前枚举的 的倍数,

如果数量只有零个,呢么就不用选择区间 ,初始区间的 就是当前枚举的 的倍数。
如果数量只有一个,那么就是在这个位置到最后的位置的区间都加 x,
如果数量只有两个,还需要判断这两个数是不是关于 当前枚举 互补 ,设两个位置分别为 ,那么区间就是
如果数量大于两个,呢么一定没有合法答案。

因为我们枚举的的答案中也包含了最大答案的 ,所以取最大值即可得到答案。

当选择的区间不包含最后数 时同理

代码
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define endl '\n'
#define double long double
#define PII pair<int,int>
#define F first 
#define S second 
#define int long long
#define i128 __int128_t
#define all(vec) vec.begin(),vec.end()  
#define vi vector<int>   
#define vii vector<vector<int>>   
using namespace std;
const int N = 5e5+10 ;
const int M = 1e3+10 ;
const int INF = 0x3f3f3f3f3f3f3f3f;
const int MOD1 = 1e9 + 7 ;
const int MOD2 = 998244353 ;
const double eps = 1e-9 ;
int gcd(int a, int b){ return b == 0 ? a : gcd(b, a%b); }
int lcm(int a, int b){ return a * b / gcd(a,b); } 
int _ = 1 ;
int ans = 0 ;
int n , m, k, q ;

void solve(){
    ans = 1 ;
    cin >> n ;
    vi a(n + 1,0) ;
    vi b(n + 1,0) ;
    bool f1 = true ;
    for(int i = 1; i <= n ; ++ i){
        cin >> a[i] ;
        if(i >= 2 && a[i] != a[i-1]) f1 = false ;
        b[i] = a[i] - a[i-1] ;
    }
    if(f1){
        cout << 0 << endl ;
        return ;
    }
    int t1 = 0 ;
    for(int i = 2 ; i <= n ; ++ i){
        t1 = gcd(t1, b[i]) ;
    }
    ans = abs(t1) ;

    auto clac = [&]() -> void {
        vi vec1 ;
        for(int i = 1 ; i * i <= a[1] ; ++ i){
            if(a[1] % i == 0){
                vec1.push_back(i) ;
                if(a[1] / i != i){
                    vec1.push_back(a[1] / i) ;
                }
            }
        }

        for(auto e : vec1){
            vi vecte ;
            bool f =true ;
            int cnt = 0 ;
            int la = 0 ;
            for(int i = 2 ; i <= n ; ++ i){
                if(b[i] % e != 0){ 
                    if(cnt == 0){
                        la = b[i] ;
                        f = true ;
                    }else if(cnt == 1){
                        if((b[i] + la) % e == 0){
                            f = true ;
                        }else{
                            f = false ;
                        }
                    }else{
                        f = false ;
                        break ; 
                    }
                    cnt ++ ;
                }

            }
            if(f) ans = max(ans,e) ;
        }
    };
    clac() ;
    reverse(a.begin() + 1, a.end()) ;
    for(int i = 1; i <= n ; ++ i){
        b[i] = a[i] - a[i-1] ;
    }
    clac() ;
    cout << ans << endl ;
}

signed main(){
    IOS ;
    cin >> _ ;
    while(_ --){
        solve() ;
    }
    return 0;
}

 


 

 

 

 

 

 

我打算法竞赛,真的假的。
最后更新于 2025-08-16