2024牛客寒假算法基础集训营3

A. 智乃与瞩目狸猫、幸运水母、月宫龙虾

比较首个字母是否是不区分大小写同个字母,时间复杂度 O ( T ) O(T) O(T)

#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 lll;
typedef __uint128_t ulll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e18;
const int mod = 1e9 + 7;
const int base = 13331;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
void solve()
{
    string a;
    string b;
    cin >> a >> b;
    if(a[0]-'a' == b[0]-'a' || a[0]-'A' == b[0]-'A' || a[0]-'a' == b[0]-'A' || a[0]-'A' == b[0] - 'a')
    cout << "Yes" << '\n';
    else
    cout << "No" << '\n';
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--)
    solve();
    return 0;
}

B. 智乃的数字手串

不能操作的最后一个状态一定是奇偶相间且长度为偶数的串,所以直接判断初始串长度为奇或偶,时间复杂度 O ( N T ) O(NT) O(NT)

#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 lll;
typedef __uint128_t ulll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e18;
const int mod = 1e9 + 7;
const int base = 13331;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
int a[N];
void solve()
{
    int n;
    cin >> n;
    int t1 = 0, t2 = 0;
    for(int i = 1;i <= n;i++)
    cin >> a[i];
    if(n % 2 == 0)
    cout << "zn" << '\n';
    else
    cout << "qcjj" << '\n';
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--)
    solve();
    return 0;
}

C. 智乃的前缀、后缀、回文

由于符合条件的前缀和后缀全是回文,所以我们翻转其中一个字符串之后,最后的所求即为两个字符串的最大前缀和后缀相同回文串长度之和 ∗ 2 *2 2

其中有三个条件:相同,回文串和互不覆盖

我们先找出前缀和后缀最大相同的串,切找出来的两个串可以相互覆盖,从前往后和从后往前遍历即可

找到相同的前缀后缀子串后,我们用哈希值判断子串的子串是否为回文串,将前缀和后缀的回文串长度分别存储在两个 v e c t o r vector vector中,再用二分查找符合不覆盖的两个子串,即长度之和小于等于 m i n ( n , m ) min(n,m) min(n,m),时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

(就是抄板子的时候抄错了,硬吃了几发罚时, w h a t   c a n   i   s a y what\ can\ i\ say what can i say)

#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 lll;
typedef __uint128_t ulll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e18;
const int mod = 1e9 + 7;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
ull h1[N], h2[N], p[N];
int n;
int check(int L, int R)
{
    if(h1[R] - h1[L - 1] * p[R - L + 1] == h2[n - L + 1] - h2[n - R + 1 - 1] * p[R - L + 1])
    return 1;
    else
    return 0;
}
void solve()
{
    int base = 233;
    vector<int> ans1, ans2;
    int x, y;
    cin >> x >> y;
    string a, b;
    cin >> a;
    cin >> b;
    reverse(all(a));
    string s = " ";
    for(int i = 0;i < min(x, y);i++)
    {
        if(a[i] != b[i])
        break;
        s += a[i];
        n++;
    }
    //cout << s << '\n';
    p[0] = 1;
    h1[0] = 0; //正向hash值
    h2[0] = 0;//反向hash值
    for(int i = 1; i <= n; i++)
    {
        h1[i] = h1[i-1]*base+(ull)s[i];
        h2[i] = h2[i-1]*base+(ull)s[n-i+1];
        p[i] = p[i-1]*base;
    }
    for(int i = 1;i <= n;i++)
    {
        if(check(1, i))
        {
            ans1.push_back(i);
            //cout << i << '\n';
        }
    }
    s = " ";
    n = 0;
    for(int i = 1;i <= min(x, y);i++)
    {
        if(a[x - i] != b[y - i])
        break;
        s += a[x - i];
        n++;
    }
    //cout << s << '\n';
    p[0] = 1;
    h1[0] = 0; //正向hash值
    h2[0] = 0;//反向hash值
    for(int i = 1; i <= n; i++)
    {
        h1[i] = h1[i-1]*base+(ull)s[i];
        h2[i] = h2[i-1]*base+(ull)s[n-i+1];
        p[i] = p[i-1]*base;
    }
    for(int i = n;i >= 1;i--)
    {
        if(check(1, i))
        {
            ans2.push_back(i);
            //cout << i << '\n';
        }
    }
    if(ans1.empty() || ans2.empty())
    {
        cout << "-1" << '\n';
        return;
    }
    int ans = -1;
    for(auto l1 : ans1)
    {
        int l2 = min(x, y) - l1;
        auto it = lower_bound(all(ans2), l2, greater<int>());
        if(it != ans2.end())
        ans = max(ans, l1 + *it);
    }
    if(ans == -1)
    cout << "-1" << '\n';
    else
    cout << 2 * ans << '\n';
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    //cin >> t;
    while (t--)
    solve();
    return 0;
}

D. chino’s bubble sort and maximum subarray sum(easy version)

由于是 e a s y   v e r s i o n easy\ version easy version,题目中最多有有一次相邻元素的交换,所以我们暴力求两两元素交换后的最大字段和,时间复杂度 O ( n 2 ) O(n^2) O(n2)

#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 lll;
typedef __uint128_t ulll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e18;
const int mod = 1e9 + 7;
const int base = 13331;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
int a[N], b[N];
void solve()
{
    int n, k;
    cin >> n >> k;
    for(int i = 1;i <= n;i++)
    cin >> a[i];
    int sum = 0, ans = -INF;
    for(int i = 1;i <= n;i++)
    {
        if(sum < 0)
        sum = a[i];
        else
        sum += a[i];
        ans = max(ans, sum);
    }
    if(k == 0)
    {
        cout << ans << '\n';
        return;
    }
    for(int j = 1;j < n;j++)
    {
        sum = 0;
        if(j == 1)
        swap(a[1], a[2]);
        else
        {
            swap(a[j - 1], a[j]);
            swap(a[j], a[j + 1]);
        }
        for(int i = 1;i <= n;i++)
        {
            if(sum < 0)
            sum = a[i];
            else
            sum += a[i];
            ans = max(ans, sum);
        }
    }
    cout << ans << '\n';
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    //cin >> t;
    while (t--)
    solve();
    return 0;
}

GH. 智乃的比较函数

如果输入的是 x   y   0 x\ y\ 0 x y 0,条件可以转化成 x ≥ y x\geq y xy,即 x − y ≥ 0 x-y\geq 0 xy0

如果输入的是 x   y   1 x\ y\ 1 x y 1,条件可以转化成 x < y x < y x<y,即 y − x > 0 y-x > 0 yx>0,由于 x x x y y y都是正整数,所以又可以转化为 y − x ≥ 1 y-x\geq 1 yx1

所以我们最后要求的就是在若干个不等式约束下, x , y , z x,y,z xy,z是否有解,那我们就能想到差分约束,根据约束条件建图,再用 S P F A SPFA SPFA判断是否存在负环,如果存在负环则无解,时间复杂度 O ( T N ) O(TN) O(TN)

#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 lll;
typedef __uint128_t ulll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e18;
const int mod = 1e9 + 7;
const int base = 13331;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
int n, m, dis[N], inque[N], cnt[N];
vector<pii> G[N];
int SPFA()//跑单源最短路 并且返回是否有负环
{
    queue<int> que;
    que.push(0);
    while(!que.empty())
    {
        int u = que.front();
        que.pop();
        inque[u] = 0;
        for(auto [v,val] : G[u])
        {
            if(dis[v] > dis[u] + val)
            {
                cnt[v] = cnt[u] + 1;
                dis[v] = dis[u] + val;
                if(cnt[v] >= n + 1) 
                return 0;
                if(inque[v] == 0)
                {
                    que.push(v);
                    inque[v] = 1;
                }
            }
        }
    }
    return 1;
}
void solve()
{
    n = 3;
    cin >> m;
    for(int i = 0;i <= n;i++)
    G[i].clear();
    for (int i = 1; i <= m; i++)
    {
        int x, y, z;
        cin >> x >> y >> z;
        if(z == 0)
        G[x].push_back({y, 0});
        else
        G[y].push_back({x, -1});
    }
    for(int i = 0;i <= n;i++)
    inque[i] = cnt[i] = 0;
    for(int i = 1; i <= n;i++)
    G[0].push_back({i, 0});
    for(int i = 1;i <= n;i++)
    dis[i] = INF;
    if(SPFA() == 0)
    cout << "No\n";
    else
    cout << "Yes\n";
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--)
    solve();
    return 0;
}

J. 智乃的相亲活动

总的期望等于各个分期望的和,所以我们只用求每个男嘉宾或者女嘉宾被选中的期望,最后求和

一个男嘉宾被其中一个对他有好感的异性选中的概率是 1 m \frac{1}{m} m1 m m m为这个异性总共的有好感的男嘉宾个数,所以该男嘉宾被选上的期望为 1 − ∏ 1 n ( 1 − 1 m ) 1-\prod^{n}_{1}(1-\frac{1}{m}) 11n(1m1),时间复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 lll;
typedef __uint128_t ulll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e18;
const int mod = 1e9 + 7;
const int base = 13331;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
vector<int> G1[N], G2[N];
void solve()
{
    int n, m, q;
    double ans1 = 0, ans2 = 0;
    cin >> n >> m >> q;
    for(int i = 1;i <= q;i++)
    {
        int u, v;
        cin >> u >> v;
        G1[u].push_back(v);
        G2[v].push_back(u);
    }
    for(int i = 1;i <= n;i++)
    {
        double res = 1;
        for(auto u : G1[i])
        {
            res = res * (1.0  * (double)(G2[u].size() - 1) / (double)G2[u].size());
        }
        ans1 += 1 - res;
    }
    for(int i = 1;i <= m;i++)
    {
        double res = 1;
        for(auto u : G2[i])
        {
            res = res * (1.0  * (double)(G1[u].size() - 1) / (double)G1[u].size());
        }
        ans2 += 1 - res;
    }
    cout << "float" << '\n';
    cout << fixed << setprecision(7) << ans1 << " " << ans2 << '\n';
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    //cin >> t;
    while (t--)
    solve();
    return 0;
}

K. 智乃的“黑红树”

从上到下建树,建树时别把黑节点和红节点搞混就行,时间复杂度 O ( a + b ) O(a+b) O(a+b)

#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 lll;
typedef __uint128_t ulll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e18;
const int mod = 1e9 + 7;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
void solve()
{
    queue<int> re, bl;
    int a, b;
    cin >> a >> b;
    int sum = a + b;
    vector<int> l(sum+1,-1), r(sum+1,-1);
    re.push(1);
    a--;
    int now = 1;
    for(int i = 1;i <= sum;i++)
    {
        if(re.size() && b >= 2)
        {
            int tp = re.front();
            re.pop();
            l[tp] = ++now;
            bl.push(now);
            r[tp] = ++now;
            bl.push(now);
            b -= 2;
        }
        if(bl.size() && a >= 2)
        {
            int tp = bl.front();
            bl.pop();
            l[tp] = ++now;
            re.push(now);
            r[tp] = ++now;
            re.push(now);
            a -= 2;
        }
    }
    if(a == 0 && b == 0)
    {
        cout << "Yes" << '\n';
        for(int i = 1;i <= sum;i++)
        cout << l[i] << " " << r[i] << '\n';
    }
    else
    cout << "No" << '\n';
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--)
    solve();
    return 0;
}

LM. 智乃的36倍数

我们发现,一个数对 36 36 36取模的值和它拆分成前后两个部分分别对 36 36 36取模的值之和后再取模 36 36 36相同,例如 3429 % 36 = ( 3400 % 36 + 29 % 36 ) % 36 = ( 16 + 29 ) % 36 = 9 3429\%36=(3400\%36+29\%36)\%36=(16+29)\%36=9 3429%36=(3400%36+29%36)%36=(16+29)%36=9

因为 1 ≤ a i ≤ 1 0 18 1 \leq a_i \leq 10^{18} 1ai1018,所以每个整数后面最多拼接长度为 18 18 18的整数,所以对于每个整数,我们求它后面添加长度为 [ 1 , 18 ] [1,18] [1,18] 0 0 0后对 36 36 36取模的值,然后遍历题目给定的每个整数,如果这个整数后面拼接 0 0 0的个数等于某个给定的数的长度并且对 36 36 36取模的值相同,则 a n s + + ans++ ans++

注意判断模数为 0 0 0的情况和自己拼接到自己上的情况,时间复杂度 O ( 18 n ) O(18n) O(18n)

#include <bits/stdc++.h>
#define int long long
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef __int128 lll;
typedef __uint128_t ulll;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int INF = 1e18;
const int mod = 1e9 + 7;
const int base = 13331;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
int a[N], b[N];
void solve()
{
    int n;
    cin >> n;
    map<pii, int> cnt;
    for(int i = 1;i <= n;i++)
    b[i] = 0;
    for(int i = 1;i <= n;i++)
    {
        cin >> a[i];
        int tt = a[i];
        while(tt > 0)
        {
            b[i]++;
            tt = tt / 10;
        }
        cnt[{b[i], a[i] % 36}]++;
    }
    int ans = 0;
    for(int i = 1;i <= n;i++)
    {
        int res = a[i];
        for(int j = 1;j <= 18;j++)
        {
            res = res % 36 * 10 % 36;
            int now;
            if(res == 0)
            now = 0;
            else
            now = 36 - res;
            ans += cnt[{j, now}];
            if(b[i] == j && a[i] % 36 == now)
            ans--;
        }
    }
    cout << ans << '\n';
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    //cin >> t;
    while (t--)
    solve();
    return 0;
}
  • 45
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值