牛客小白月赛73

A 最小的数字

#include <bits/stdc++.h>

using namespace std;

#define int long long

int32_t main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int n;
    cin >> n;
    cout << ((n+2ll)/3ll)*3ll << "\n";
    return 0;
}

B 优美的GCD

#include <bits/stdc++.h>

using namespace std;

#define int long long

int32_t main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t;
    cin >> t;
    while( t -- ){
        int n ;
        cin >> n;
        cout << n << " " << n*2 << "\n";
    }
    return 0;
}

C 优美的序列

#include <bits/stdc++.h>

using namespace std;

#define int long long

void solve(){
    int n;
    cin >> n;
    vector<int> a(n);
    for( auto &i : a ) cin >> i;
    sort( a.begin(), a.end() );
    for( int i = 1 ; i < n ; i ++ ){
        if( a[i] == a[i-1] ){
            cout << "-1\n";
            return ;
        }
    }
    for( auto i : a )
        cout << i << " ";
    cout << "\n";
}

int32_t main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t;
    cin >> t;
    while( t -- )
        solve();
    return 0;
}

DE Kevin喜欢零

没有写简单版本。

首先知道的是,末尾的\(0\),一定是区间内\(2,5\)的数量决定的,如果可以计算出\(2,5\)的数量的最小值,就可以知道答案。

我们可以用前缀和维护\(2,5\)的数量,因为前缀和的单调性,所以可以枚举左端点并二分出右端点的取值范围。

#include <bits/stdc++.h>

using namespace std;

#define int long long

void solve(){
    int n , k;
    cin >> n >> k;
    vector<int> a(n+1) , b(n+1);
    for( int i = 1 , x ; i <= n ; i ++ ){
        cin >> x;
        while( x % 2 == 0 ) x /= 2 , a[i] ++;
        while( x % 5 == 0 ) x /= 5 , b[i] ++;
    }

    for( int i = 1 ; i <= n ; i ++ )
        a[i] += a[i-1] , b[i] += b[i-1];

    auto f = [a,b]( int l , int r ){
        return min( a[r] - a[l-1] , b[r] - b[l-1] );
    };


    int res = 0;
    for( int i = 1 , x , y , l , r , mid ; i <= n ; i ++ ) {
        l = i, r = n, x = -1;
        while (l <= r) {
            mid = (l + r) >> 1;
            if (f(i, mid) >= k) x = mid, r = mid - 1;
            else l = mid + 1;
        }
        l = i, r = n, y = -1;
        while (l <= r) {
            mid = (l + r) >> 1;
            if (f(i, mid) <= k) y = mid, l = mid + 1;
            else r = mid - 1;
        }
        if (x == -1 || y == -1) continue;
        if (f(i, x) != k || f(i, y) != k ) continue;
        res += max( 0ll, y - x + 1);
    }
    cout << res << "\n";
}

int32_t main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int t;
    cin >> t;
    while( t -- ) solve();
    return 0;
}

F Kevin的哈希构造

比较经典的 dp 思路吧。

\(f[i][j][x]\)表示前\(i\)位恰好\(j\)位相同且哈希值为\(x\)的方案是否存在。我们枚举状态后,在枚举出当前位选的字母\(c\),则状态转移方程为\(f[i+1][j+(c=s_i)][(x\times b + c ) \mod p] |= f[i][j][x]\)

我们再维护前缀状态就可以还原出一个合法的串。

#include<bits/stdc++.h>

using namespace std;

#define int long long

#define V vector

#define ll long long
#define mp make_pair

int hashMod(string s, int b, int p) {
    int ans = 0;
    for (auto c: s)
        ans = (ans * b + c - 'a' + 1) % p;
    return ans;
}

int power(int x, int y, int p) {
    int ans = 1;
    while (y) {
        if (y & 1) ans = ans * x % p;
        x = x * x % p, y >>= 1;
    }
    return ans;
}

void solve() {
    int n, base, mod, k;
    string s;
    cin >> n >> base >> mod >> k >> s;

    V<V<V<bool>>> f(n + 1, V<V<bool>>(k + 2, V<bool>(mod + 1, 0)));
    V<V<V<int>>> preC(n + 1, V<V<int>>(k + 2, V<int>(mod + 1)));
    V<V<V<int>>> preH(n + 1, V<V<int>>(k + 2, V<int>(mod + 1)));

    int H = 0; // 计算原串 Hash 值
    for (auto c: s) H = (H * base + c - 'a' + 1) % mod;

    f[0][0][0] = 1;
    for (int i = 0; i < n; i++)
        for (int j = 0; j <= k; j++)
            for (int x = 0; x < mod; x++)
                if (f[i][j][x]){
                    for (int c = 'a', nxt; c <= 'z'; c++) {
                        nxt = (x * base + c - 'a' + 1 + mod) % mod;
                        if (c == s[i]) {
                            f[i + 1][j + 1][nxt] = 1;
                            preC[i + 1][j + 1][nxt] = c;
                            preH[i + 1][j + 1][nxt] = x;
                        } else {
                            f[i + 1][j][nxt] = 1;
                            preC[i + 1][j][nxt] = c;
                            preH[i + 1][j][nxt] = x;
                        }
                    }

                }

    if (!f[n][k][H]) {
        cout << "-1\n";
        return;
    }
    string res = "";
    for (int i = n, j = k, x = H; i >= 1; i--) {
        res += (char) preC[i][j][x];
        if (preC[i][j][x] == s[i - 1]) x = preH[i][j][x], j--;
        else x = preH[i][j][x];
    }
    reverse(res.begin(), res.end());
    cout << res << "\n";

}

int32_t main() {
    int t;
    cin >> t;
    for (; t; t--)
        solve();
}

G MoonLight的冒泡排序难题

打表找规律,发现分子的数列是\(0,1,7,46,326,2556,\cdots\),然后查到分子的值的递推式是\(a_i=a_{i-1}\times i + (i-1)(i-1)!\)

分子其实就是全排列

#include <bits/stdc++.h>

using namespace std;

#define int long long
const int mod = 998244353;

int power( int x , int y ){
    int ans = 1;
    while( y ){
        if( y & 1 ) ans = ans * x % mod;
        x = x * x % mod , y >>= 1;
    }
    return ans;
}

int inv( int x ){
    return power( x , mod - 2 );
}

const int N = 2e5+5;

int32_t main() {
    ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);

    vector<int> fact(N+1) , invFact(N+1) , f(N+1);
    fact[0] = 1 , invFact[0] = inv( fact[0] );
    for( int i = 1; i <= N ; i ++ )
        fact[i] = fact[i-1] * i % mod , invFact[i] = inv(fact[i]);
    f[1] = 0;
    for( int i = 2 ; i <= N ; i ++ )
        f[i] = ( f[i-1]*i % mod + (i-1)*fact[i-1] % mod ) % mod;

    int t ;
    cin >> t;
    while( t -- ){
        int x;
        cin >> x;
        cout << f[x] * invFact[x] % mod << "\n";
    }
    return 0;
}
/*
 * 0 1 7 46 326 2556 22212 212976
 */
posted @ 2023-06-01 22:18  PHarr  阅读(11)  评论(0编辑  收藏  举报