2024牛客暑期多校训练营8

A. Haitang and Game

通过审题可以知道,最后的胜者和若干次操作后最多能增加的数的奇偶有关。

由于 a i a_i ai 较小,所以我们枚举每一个没出现过的 x , x ∈ [ 1 , 1 e 5 ] x,x\in[1,1e5] x,x[1,1e5], 考虑如何让 x x x 出现,很简单,有两个数的 g c d gcd gcd 等于 x x x 呗,好像说了废话

那我们怎么快速寻找这么两个数呢,在遍历 x x x 的时候查找它的所有倍数,如果出现过并且这些所有的倍数 g c d gcd gcd 值为 x x x 的话则 x x x 可以出现。如果 x % 2 = 1 x\%2=1 x%2=1 先手获胜,否则后手获胜,时间复杂度 O ( T n l o g n ) O(Tnlogn) O(Tnlogn)

#include <bits/stdc++.h>
#define int long long
using namespace std;
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int M = 1e6 + 10;
const int INF = 1e18 + 10;
const int mod = 1e9 + 7;
const int base = 23333;
const double pi = acos(-1.0);
//mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());
int a[N];
void solve()
{
    vector<int> jl(1e5 + 10, 0);
    int n;
    cin >> n;
    for(int i = 1;i <= n;i++)
    {
        cin >> a[i];
        jl[a[i]] = 1;
    }
    int cnt = 0;
    for(int i = 1;i <= 1e5;i++)
    {
        if(jl[i]) continue;
        int flag = 0, now = 0;
        for(int j = i;j <= 1e5;j += i)
        {
            if(jl[j])
            {
                if(flag == 0)
                {
                    now = j;
                    flag = 1;
                }
                else now = __gcd(now, j);
            }
        }
        if(now == i) cnt++;
    }
    if(cnt % 2 == 1) cout << "dXqwq" << '\n';
    else cout << "Haitang" << '\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.Haitang and Math

赛时一直在调 O ( T n ) O(T\sqrt{n}) O(Tn ) 的做法,但是没调出来,都这么轻量级了还不让过,真是可恶。

比赛结束之后才发现居然有 P o l l a r d   R h o Pollard\ Rho Pollard Rho 这样的黑科技,可以在 n 4 \sqrt[4]{n} 4n 的时间复杂度求得一个数的最大质因子,真是学到了。

求出最大质因子之后就可以通过质因子分解分解出所有的质因子,再通过 d f s dfs dfs 求出所有的因子,对于 [ 1 , 108 ] [1,108] [1,108] 的所有 S ( m ) S(m) S(m) 求一下题目中的式子是否成立即可,注意去重。时间复杂度有点玄学,大概是 O ( T n l o g n ) O(\frac{T\sqrt{n}}{logn}) O(lognTn ),交上去之后跑的飞起,这个故事告诉我们,学好算法还是很重要滴。

#include <bits/stdc++.h>
#define int long long
using namespace std;
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 100;
const int M = 1e6 + 10;
const int INF = 1e18 + 100;
const int mod = 1e9 + 7;
const int base = 23333;
// mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());
int max_factor, n, nn;
int quick_pow(int x, int p, int mod) // 快速幂
{
    int ans = 1;
    while (p)
    {
        if (p & 1) ans = (__int128)ans * x % mod;
        x = (__int128)x * x % mod;
        p >>= 1;
    }
    return ans;
}
bool Miller_Rabin(int p) // 判断素数
{
    if (p < 2) return 0;
    if (p == 2) return 1;
    if (p == 3) return 1;
    int d = p - 1, r = 0;
    while (!(d & 1)) ++r, d >>= 1; // 将d处理为奇数
    for (int k = 0; k < 10; ++k)
    {
        int a = rand() % (p - 2) + 2;
        int x = quick_pow(a, d, p);
        if (x == 1 || x == p - 1) continue;
        for (int i = 0; i < r - 1; ++i)
        {
            x = (__int128)x * x % p;
            if (x == p - 1) break;
        }
        if (x != p - 1) return 0;
    }
    return 1;
}
int Pollard_Rho(int x)
{
    int s = 0, t = 0;
    int c = (int)rand() % (x - 1) + 1;
    int step = 0, goal = 1;
    int val = 1;
    for (goal = 1;; goal *= 2, s = t, val = 1) // 倍增优化
    {
        for (step = 1; step <= goal; ++step)
        {
            t = ((__int128)t * t + c) % x;
            val = (__int128)val * abs(t - s) % x;
            if ((step % 127) == 0)
            {
                int d = __gcd(val, x);
                if (d > 1) return d;
            }
        }
        int d = __gcd(val, x);
        if (d > 1) return d;
    }
}
void fac(int x)
{
    if (x <= max_factor || x < 2) return;
    if (Miller_Rabin(x)) // 如果x为质数
    {
        max_factor = max(max_factor, x); // 更新答案
        return;
    }
    int p = x;
    while (p >= x) p = Pollard_Rho(x); // 使用该算法
    while ((x % p) == 0) x /= p;
    fac(x), fac(p); // 继续向下分解x和p
}
vector<int> pri;
map<int, int> mp, cnt;
int ans;
int coun(int x)
{
    int res = 0;
    while(x > 0)
    {
        res += x % 10;
        x /= 10;
    }
    return res;
}
void dfs(int now, int res, int tt)
{
    //cout << now << " " << res << " " << tt << '\n';
    if(res > tt) return;
    if(now == pri.size())
    {
        if(tt % res == 0 && n % res != 0 && !cnt[res] && coun(res) == n - tt)
        {
            //cout << res << '\n';
            cnt[res] = 1;
            ans++;
        }
        return;
    }
    dfs(now + 1, res, tt);
    if(mp[pri[now]])
    {
        mp[pri[now]]--;
        dfs(now, res * pri[now], tt);
        mp[pri[now]]++;
    }
}
void solve()
{
    srand((unsigned)time(NULL));
    cin >> n;
    ans = 0;
    cnt.clear();
    for(int ii = 1;ii <= min(n - 2, 108LL);ii++)
    {
        pri.clear();
        mp.clear();
        max_factor = 0;
        nn = n - ii;
        fac(nn);
        pri.push_back(max_factor);
        nn /= max_factor;
        mp[max_factor]++;
        for(int i = 2; i <= nn / i; ++i) 
        {
            if(nn % i == 0)
            {
                pri.push_back(i);
                while (nn % i == 0) 
                {
                    mp[i]++;
                    nn /= i;
                }
            }
        }
        if (nn > 1)
        {
            mp[nn]++;
            pri.push_back(nn);
        }
        //cout << n - ii << " " << pri.size() << '\n';
        //for(auto u : pri) cout << u << " " << mp[u] << '\n';
        dfs(0, 1, n - ii);
    }
    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;
}

J. Haitang and Triangle

n n n 个数相邻三三组合最多有 n − 2 n-2 n2 种组合方式,但是包含 1 1 1 的那一组一定组成不了三角形,所以 k = n − 2 k=n-2 k=n2 时无解。

k = 0 k=0 k=0 时,形如 d , 2 d , 3 d , d − 1 , 2 d − 1 , 3 d − 1 , … , 1 , 1 + d , 1 + 2 d d,2d,3d,d-1,2d-1,3d-1,\dots,1,1+d,1+2d d,2d,3d,d1,2d1,3d1,,1,1+d,1+2d 这样的排列是满足条件的, d = ⌊ ( n − k ) 3 ⌋ d=\lfloor \frac{(n-k)}3 \rfloor d=3(nk)

k > 0 k>0 k>0 怎么放呢,不难发现,把除了 1 1 1 的其他 m m m 个数按顺序发如 2 , 3 , 4 , … , m 2,3,4,\dots,m 2,3,4,,m,每个长度为三的字串都能构成一个三角形,所以我们左边放 k = 0 k=0 k=0 时的情况,右边放其他数。再根据 d % 3 d\%3 d%3 的不同值往端点插入数,增加构不成三角形的区间长度,时间复杂度 O ( ∑ n ) O(\sum{n}) O(n)

#include <bits/stdc++.h>
#define int long long
using namespace std;
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 100;
const int M = 1e6 + 10;
const int INF = 1e18 + 100;
const int mod = 1e9 + 7;
const int base = 23333;
// mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count())
void solve()
{
    int n, m;
    cin >> n >> m;
    vector<int> flag(n + 5);
    if(m == n - 2)
    {
        cout << -1 << '\n';
        return;
    }
    int x = n - m;
    int d = x / 3;
    vector<int> ans;
    if (x % 3 == 0) 
    {
        for (int i = 0;i < d;i++) 
        {
            ans.push_back(d - i);
            ans.push_back(2 * d - i);
            ans.push_back(3 * d - i);
        }
        for (int i = 1;i <= m;i++) ans.push_back(3 * d + i);
    }
    if (x % 3 == 1) 
    { 
        ans.push_back(n);
        for (int i = 0;i < d;i++) 
        {
            ans.push_back(d - i);
            ans.push_back(2 * d - i);
            ans.push_back(3 * d - i);
        }
        for (int i = 1;i <= m;i++) ans.push_back(3 * d + i);
    }
    if (x % 3 == 2) 
    {
        ans.push_back(3 * d + 1);
        for (int i = 0;i < d;i++) 
        {
            ans.push_back(d - i);
            ans.push_back(2 * d - i);
            ans.push_back(3 * d - i);
        }
        ans.push_back(3 * d + 2);
        for (int i = 3;i <= m + 2;i++) ans.push_back(3 * d + i);
    }
    for (auto x : ans) cout << x << " ";
    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;
}

K. Haitang and Ava

从前往后匹配 a v a ava ava 或者 a v a v a avava avava 串,如果能匹配完输出 Y e s Yes Yes ,否则输出 N o No No ,时间复杂度 O ( ∑ S ) O(\sum{S}) O(S)

#include <bits/stdc++.h>
#define int long long
using namespace std;
#define YES "YES"
#define NO "NO"
#define all(a) a.begin(), a.end()
typedef long long ll;
typedef unsigned long long ull;
typedef long double ld;
typedef pair<int, int> pii;
const double eps = 1e-9;
const int N = 1e6 + 10;
const int M = 1e6 + 10;
const int INF = 1e18 + 10;
const int mod = 1e9 + 7;
const int base = 23333;
const double pi = acos(-1.0);
//mt19937 rng(std::chrono::steady_clock::now().time_since_epoch().count());
void solve()
{
    string s;
    cin >> s;
    int pos = 0;
    for(int i = 0;i < s.size();)
    {
        if(i + 5 <= s.size())
        {
            if(s[i] == 'a' && s[i + 1] == 'v' && s[i + 2] == 'a' && s[i + 3] == 'v' && s[i + 4] == 'a')
            {
                i += 5;
                pos = i;
            }
            else if(s[i] == 'a' && s[i + 1] == 'v' && s[i + 2] == 'a')
            {
                i += 3;
                pos = i;
            }
            else break;
        }
        else if(i + 3 <= s.size())
        {
            if(s[i] == 'a' && s[i + 1] == 'v' && s[i + 2] == 'a')
            {
                i += 3;
                pos = i;
            }
            else break;
        }
        else break;
    }
    if(pos == s.size()) 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;
}
  • 6
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值