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

A. mutsumi的质数合数

只有 1 1 1既不是质数也不是合数,总数减去 1 1 1的个数,时间复杂度 O ( n ) O(n) O(n)

#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 = 2e6 + 10;
const int INF = 1e16;
const int mod = 998244353;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
void solve()
{
    int n;
    cin >> n;
    int t1 = 0;
    for(int i = 1;i <= n;i++)
    {
        int tt;
        cin >> tt;
        if(tt != 1)
        t1++;
    }
    cout << t1 << '\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. tomorin的字符串迷茫值

先来考虑有哪些字符串通过合法删除可以获得 m y g o mygo mygo

m y g o , m # y g o , m y # g o , m y g # o , m # y # g o , m # y g # o , m y # g # o , m # y # g # o mygo, m\#ygo, my\#go, myg\#o, m\#y\#go, m\#yg\#o, my\#g\#o, m\#y\#g\#o mygo,m#ygo,my#go,myg#o,m#y#go,m#yg#o,my#g#o,m#y#g#o只有这八个串可行, # \# #对字符没有要求,考虑完这个之后,我们再来考虑两边的字符,它们无论怎么删除都不会影响到现在这个串

所以每当我们发现这么一个串的时候,要分别乘上左右两边字符的删除方案

通过举例发现,字符的删除方案刚好是斐波那契数列,如 a a aa aa 3 3 3 a a a aaa aaa 5 5 5等,时间复杂度 O ( 40 n ) O(40n) O(40n)

#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 = 2e6 + 10;
const int INF = 1e16;
const int mod = 1e9 + 7;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
int f[N];
void solve()
{
    string s;
    cin >> s;
    int n = s.size();
    s = " " + s;
    f[0] = 1;
    f[1] = 2;
    for(int i = 2;i <= 1e6;i++)
    f[i] = (f[i - 1] + f[i - 2]) % mod;
    vector<string> a = {"mygo", "m#ygo", "my#go", "myg#o", "m#y#go", "m#yg#o", "my#g#o", "m#y#g#o"};
    int ans = 0;;
    for(int i = 1;i <= n;i++)
    {
        for(auto t : a)
        {
            if(t.size() + i - 1 > n)
            break;
            int flag = 0;
            for(int j = 0;j < t.size();j++)
            {
                if(t[j] == '#')
                continue;
                else
                {
                    if(t[j] != s[i + j])
                    {
                        flag = 1;
                        break;
                    }
                }
            }
            if(flag == 0)
            ans = (ans + f[i - 1] * f[n - i - t.size() + 1] % mod) % mod;
        }
    }
    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;
}

C. anon的私货

奇迹行者还在 w a wa wa

能放在左边就尽量放在左边,最后一个数要把多出来的放在右边

每次放 m i n ( a [ i ] , a [ i − 1 ] ) − 1 min(a[i], a[i - 1]) - 1 min(a[i],a[i1])1个,时间复杂度 O ( n ) O(n) O(n)

#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 = 2e6 + 10;
const int INF = 1e16;
const int mod = 998244353;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
int a[N];
void solve()
{
    int n;
    cin >> n;
    for(int i = 1;i <= n;i++)
    cin >> a[i];
    if(n == 1)
    {
        cout << a[1] - 1 << '\n';
        return;
    }
    a[0] = INF;
    a[n + 1] = INF;
    int ans = 0;
    for(int i = 1;i <= n + 1;i++)
    {
        int mn = min(a[i], a[i - 1]) - 1;
        ans += mn;
        a[i] -= mn;
    }
    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;
}

E. soyorin的数组操作(easy)

如果 n n n为偶数的话,一直操作最后一个数,一定可以达到要求

如果 n n n为奇数的话,从后往前操作,每次都把当前这个数操作到不能操作为止,即操作到 a [ i ] < = a [ i + 1 ] a[i] <= a[i + 1] a[i]<=a[i+1] a [ i ] + i > a [ i + 1 ] a[i] + i > a[i + 1] a[i]+i>a[i+1],如果操作完之后出现 a [ i ] > a [ i + 1 ] a[i] > a[i + 1] a[i]>a[i+1]或者 a [ i ] < [ i − 1 ] a[i] < [i - 1] a[i]<[i1]则不行,时间复杂度 O ( n ) O(n) O(n)

#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 = 2e6 + 10;
const int INF = 1e16;
const int mod = 998244353;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
int a[N];
void solve()
{
    int n;
    cin >> n;
    for(int i = 1;i <= n;i++)
    cin >> a[i];
    if(n % 2 == 0)
    {
        cout << YES << '\n';
        return;
    }
    int cnt = 0;
    for(int i = n - 1;i >= 2;i -= 2)
    {
        int c = a[i + 1] - a[i];
        if(cnt + c < 0)
        {
            cout << NO << '\n';
            return;
        }
        int nowc = (cnt + c) / i; // 最多加几次
        cnt += nowc;
        int cc = a[i] - a[i - 1];
        if(cc + cnt < 0)
        {
            cout << NO << '\n';
            return;
        }
    }
    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;
}

F. soyorin的数组操作(hard)

(写这题的时候脑子抽了,完全抛弃了 E E E题的思路,要是 E E E题上修改,我将会是个多么阳光开朗的小男孩)

如果 n n n为偶数的话,由于操作若干次最后一个数后一定可行,所以我们看最后一个数操作多少次后符合题意。由于每次操作后后一个数都比前一个数大 1 1 1,所以 a n s = m a x ( a n s , a [ i ] − a [ i − 1 ] ) ans = max(ans, a[i] - a[i - 1]) ans=max(ans,a[i]a[i1])

如果 n n n为奇数的话,由于上一题已经判断过什么时候可行,且计算出来的 c n t cnt cnt是操作所需的最大次数,所以我们在这个基础上修改即可。

同样从后往前操作,如果 a [ i ] > a [ i + 1 ] a[i] > a[i + 1] a[i]>a[i+1],我们可以通过操作后面的数使得 a [ i ] = a [ i + 1 ] a[i] = a[i + 1] a[i]=a[i+1],由于一定可行,所以我们直接操作 a [ i ] − a [ i + 1 ] a[i] - a[i + 1] a[i]a[i+1]次,此时已经满足 a [ i ] < = a [ i + 1 ] a[i] <= a[i + 1] a[i]<=a[i+1],再来考虑 a [ i ] > = a [ i − 1 ] a[i] >= a[i - 1] a[i]>=a[i1],如果 a [ i ] < a [ i − 1 ] a[i] < a[i - 1] a[i]<a[i1],操作 a [ i − 1 ] − a [ i ] a[i - 1] - a[i] a[i1]a[i]次即可,时间复杂度 O ( n ) O(n) O(n)

由于是基于上一题代码修改,所以代码冗余较大

#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 = 2e6 + 10;
const int INF = 1e16;
const int mod = 998244353;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
int a[N];
void solve()
{
    int n;
    cin >> n;
    for(int i = 1;i <= n;i++)
    cin >> a[i];
    if(n % 2 == 0)
    {
        int ans = 0;
        for(int i = 1;i < n;i++)
        ans = max(ans, a[i] - a[i + 1]);
        cout << ans << '\n';
    }
    else
    {
        int cnt = 0;
        for(int i = n - 1;i >= 2;i -= 2)
        {
            int c = a[i + 1] - a[i];
            if(cnt + c < 0)
            {
                cout << "-1" << '\n';
                return;
            }
            int nowc = (cnt + c) / i; // 最多加几次
            cnt += nowc;
            int cc = a[i] - a[i - 1];
            if(cc + cnt < 0)
            {
                cout << "-1" << '\n';
                return;
            }
        }
        int have = 0; // 已经加了几次
        for(int i = n - 1;i >= 2;i--)
        {
            int c = a[i + 1] - a[i] + have;
            int cc = a[i - 1] - a[i] - have;
            if(c < 0)
            {
                have -= c;
                c = 0;
                cc += c;
            }
            if(cc > 0)
            have += cc;
        }
        cout << have << '\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. sakiko的排列构造

从后往前看,当前下标为 n n n,每次从前往后找一个数 i i i,使得这个数加上当前下标之和为一个质数,然后对应的 [ i , n ] [i,n] [i,n]位置输出 [ n , i ] [n,i] [n,i],从后往前找完所有的数即可,时间复杂度 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 = 2e6 + 10;
const int INF = 1e16;
const int mod = 998244353;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
int a[N];
int pd(int n)
{
    for(int i = 2;i <= sqrt(n);i++)
    {
        if(n % i == 0)
        return 0;
    }
    return 1;
}
pii ans[N];
void solve()
{
    int n, m = 0;
    cin >> n;
    int r = n, l = n;
    while(r > 0)
    {
        for(int i = 1;i <= r;i++)
        {
            if(pd(i + r))
            {
                l = i;
                ans[++m] = {l, r};
                r = i - 1;
                break;
            }
        }
    }
    for(int i = m;i >= 1;i--)
    {
        for(int j = ans[i].second;j >= ans[i].first;j--)
        cout << j << " ";
    }
    cout << '\n';
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    //cin >> t;
    while (t--)
    solve();
    return 0;
}

I. rikki的最短路

0 , t , a 0, t, a 0,t,a八种情况分类讨论,时间复杂度 O ( 1 ) O(1) O(1)

#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 = 2e6 + 10;
const int INF = 1e16;
const int mod = 998244353;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
void solve()
{
    int t, a, k;
    cin >> t >> a >> k;
    if(0 <= a && a <= t || t <= a && a <= 0)
    cout << abs(t) << '\n';
    else if(0 <= t && t <= a || a <= t && t <= 0)
    cout << abs(2 * a - t) << '\n';
    else if(a <= 0 && 0 <= t)
    {
        if(a + k >= 0)
        cout << t - 2 * a << '\n';
        else
        cout << 3 * t - 2 * a << '\n';
    }
    else
    {
        if(a - k <= 0)
        cout << 2 * a - t << '\n';
        else
        cout << 2 * a - 3 * t << '\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. rikki的数组陡峭值

当前区间无穷大,每次读入区间后,比较当前区间和读入区间是否有交集,如果有交集则一定能取到一个数使得两个区间都包含这个数,然后更新当前区间。如果两个区间没有交集,则只能在读入区间里选取左端点或者右端点,区间也就退化为点。后面再次读入区间后只用判断读入区间是否包含这个点,时间复杂度 O ( n ) O(n) O(n)

#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 = 2e6 + 10;
const int INF = 1e16;
const int mod = 998244353;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
void solve()
{
    int n;
    cin >> n;
    int l = 0, r = 1e9 + 5, pos;
    int flag = 1;
    int ans = 0;
    for(int i = 1;i <= n;i++)
    {
        int x, y;
        cin >> x >> y;
        if(flag)
        {
            if(x >= r)
            {
                flag = 0;
                ans += x - r;
                pos = x;
            }
            else if(y <= l)
            {
                flag = 0;
                ans += l - y;
                pos = y;
            }
            else
            {
                l = max(l, x);
                r = min(r, y);
            }
        }
        else
        {
            if(x <= pos && y >= pos)
            continue;
            else if(x > pos)
            {
                ans += x - pos;
                pos = x;
            }
            else
            {
                ans += pos - y;
                pos = y;
            }
        }
    }
    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;
}

K. soyorin的通知

通知给一个人的代价为 p p p,然后就是一个完全背包问题,转移方程为$ dp[j] = min(dp[j], dp[max(1LL, j - b[i])] + a[i]) ,注意把 ,注意把 ,注意把p,1 加入方案,时间复杂度 加入方案,时间复杂度 加入方案,时间复杂度O(n^2)$

#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 = 2e6 + 10;
const int INF = 1e16;
const int mod = 1e9 + 7;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
int a[N], b[N];
void solve()
{
    int n, p;
    cin >> n >> p;
    for(int i = 1;i <= n;i++)
    cin >> a[i] >> b[i];
    a[n + 1] = p;
    b[n + 1] = 1;
    vector<int> dp(n + 5);
    for(int i = 1;i <= n;i++)
    dp[i] = INF;
    dp[1] = p;
    for(int i = 1;i <= n + 1;i++)
    {
        for(int j = 2;j <= n;j++)
        {
            dp[j] = min(dp[j], dp[max(1LL, j - b[i])] + a[i]);
            //cout << i << " " << j << " " << dp[j] << '\n';
        }
    }
    cout << dp[n] << '\n';
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    //cin >> t;
    while (t--)
    solve();
    return 0;
}

L. anon的星星

a a a为胜利的局数, b b b为失败的局数, a + b = n , a − b = x a+b=n,a-b=x a+b=n,ab=x,注意正负和奇偶情况即可,时间复杂度 O ( n ) O(n) O(n)

#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 = 2e6 + 10;
const int INF = 1e16;
const int mod = 998244353;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
void solve()
{
    int n, x;
    cin >> n >> x;
    int t1 = n + x;
    int t2 = n - x;
    if(t1 % 2 == 1 || t2 % 2 == 1)
    {
        cout << "-1" << '\n';
        return;
    }
    t1 /= 2;
    t2 /= 2;
    if(t1 < 0 || t2 < 0)
    {
        cout << "-1" << '\n';
        return;
    }
    cout << t1 << " " << t2 << '\n';
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    //cin >> t;
    while (t--)
    solve();
    return 0;
}

M. mutsumi的排列连通

如果出现上下元素相同位置相同或者相隔一个位置相同则可以一次操作后满足题意,否则两次操作,注意 n = 1 , 2 n=1,2 n=1,2的情况,时间复杂度 O ( n ) O(n) O(n)

#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 = 2e6 + 10;
const int INF = 1e16;
const int mod = 998244353;
mt19937_64 rng(std::chrono::steady_clock::now().time_since_epoch().count());
int a[N], b[N];
void solve()
{
    int n;
    cin >> n;
    for(int i = 1;i <= n;i++)
    cin >> a[i];
    for(int i = 1;i <= n;i++)
    cin >> b[i];
    if(n == 1)
    cout << "-1" << '\n';
    else if(n == 2)
    {
        if(a[1] == b[1])
        cout << "-1" << '\n';
        else
        cout << "1" << '\n';
    }
    else
    {
        for(int i = 2;i < n;i++)
        {
            if(a[i] == b[i] || a[i] == b[i - 1] || a[i] == b[i + 1] || b[i] == a[i - 1] || b[i] == a[i + 1])
            {
                cout << "1" << '\n';
                return;
            }

        }
        cout << "2" << '\n';
    }
}
signed main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.tie(0);
    int t = 1;
    cin >> t;
    while (t--)
    solve();
    return 0;
}
  • 18
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值