Loading

Atcoder ABC 284题解

D Happy New Year 2023(枚举,时间复杂度计算)

题意

​ 给定 \(n \ \le \ 9 \times 10^{18}\) ,给出式子 \(n=p^2 \times q\)该式子必定有解且有唯一解。请输出 \(p\)\(q\)

思路

​ 因为式子必定有解且有唯一解,我们直接暴力枚举一下就行了。枚举上界可以看做 \(n^{\frac{1}{3}}=3 \times 10^6\)

代码

​ 没看完题目的我是 sb

const int N = 10000005;
bool isnp[N]; // is not prime: 不是素数
void init(int n)
{
    for (int i = 2; i * i <= n; i++)
        if (!isnp[i])
            for (int j = i * i; j <= n; j += i)
                isnp[j] = 1;
}
 
 
ll n;
void solve()
{
    cin >> n;
 
    for(ll i = 2; ; i ++)
    {
        if(isnp[i]) continue;
        if(n % (i * i) == 0)
        {
            cout << i << ' ' << n / (i * i) << '\n';
            return;
        }
        if(n % i == 0)
        {
            cout << (ll)(sqrt(n / i) + 0.01) << ' ' << i << '\n';
            return;
        }
    }
}
 
signed main()
{
    init(N - 1);
    int _ = 1;
    cin >> _;
    while(_--)
        solve();
}



E Count Simple Paths(爆搜,诈骗)

题意

​ 给出一个无向有环图,请问从起点1出发有多少条简单路径,若简单路径数量多于 1e6 ,输出 1e6。每个点的度数不超过10。

思路

​ 易知,答案就是顶点1到各顶点的路径和 + 1。我一开始就想爆搜,很显然在搜索树上跑一下就能出来结果,但是 \(n=200000\) 让我望而生畏。那么这题该怎么写呢?注意到简单路径数量若多于 1e6,输出 1e6 。所以直接爆搜就可以了,因为路径长度和等于简单路径数量,所以dfs的路径长度不会大于 1e6 , 若大于等于 1e6 终止搜索就可以了。所以时间复杂度是 \(O(1e6)\) 的。同时题目中限制每个点的度数的作用也就体现出来了,度数限制在一定范围的话,就可以保证爆搜的过程不会超时。

代码

const int N = 200005;
 
int n, m;
vector<int> g[N];
 
int vis[N];
int res = 0;
 
int dfs(int u)
{
    if(res >= 1e6)
        return 0;
    int sum = 1;
    for(int v : g[u])
    {
        if(vis[v])  continue;
        vis[v] = 1; 
        sum += dfs(v);
        vis[v] = 0;
    }
    res = max(res, sum);
    return sum;
}
 
 
signed main()
{
    cin >> n >> m;
    if(m == 0)
    {
        cout << 1 << '\n';
        return 0;
    }
    while(m --)
    {
        int x, y;
        cin >> x >> y;
        g[x].push_back(y);
        g[y].push_back(x);
    }
    vis[1] = 1;
    dfs(1); 
    res = min(res, 1ll * 1000000);
    cout << res << '\n';
}



F ABCBAC(字符串哈希板题)

题意

​ 定义 \(f_i(s)\) 为选取字符串 \(s\) 的前 \(i\) 个字符 + 将字符串 \(s\) 反转 + 字符串 \(s\) 的后 \(n-1\) 个字符拼接而成。

​ 现在给你一个串 \(t\) ,让你在其中找一个子串 \(f_i(s)=t\) ,输出 \(s\)\(i\) 。若没有找到,就输出 -1。

思路

​ 一眼知道怎么写,枚举一下 \(i\) 的位置,看一下哈希值是否相等就行。赛时没时间写,赛后听群友说会卡自然溢出,杜爹说以后比赛不要再写自然溢出了,这里抄一下杜爹的双哈希板子学习一下,希望有用的上的一天。

代码

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;

int n;
typedef pair<int, int> hashv;
const ll mod1 = 1000000007;
const ll mod2 = 1000000009;

hashv operator+(hashv a, hashv b)
{
    int c1 = a.first + b.first, c2 = a.second + b.second;
    if (c1 >= mod1)
        c1 -= mod1;
    if (c2 >= mod2)
        c2 -= mod2;
    return make_pair(c1, c2);
}

hashv operator-(hashv a, hashv b)
{
    int c1 = a.first - b.first, c2 = a.second - b.second;
    if (c1 < 0)
        c1 += mod1;
    if (c2 < 0)
        c2 += mod2;
    return make_pair(c1, c2);
}

hashv operator*(hashv a, hashv b)
{
    return make_pair(1ll * a.first * b.first % mod1, 1ll * a.second * b.second % mod2);
}

const int N = 2000005;
hashv pw[N], s[N], t[N]; //预处理幂次,正反两串
char tt[N];
int main()
{
    scanf("%d", &n);
    int m = 2 * n;
    scanf("%s", tt + 1);
    hashv base = make_pair(13331, 23333);
    pw[0] = make_pair(1, 1);
    for (int i = 1; i <= m; i++)
    {
        pw[i] = pw[i - 1] * base;
        s[i] = s[i - 1] * base + make_pair(tt[i], tt[i]);
    }
    for (int i = m; i >= 1; i --)
        t[i] = t[i + 1] * base + make_pair(tt[i], tt[i]);
    for (int i = 0; i <= n; i++)
    {
        hashv s1 = (s[m] - s[i + n] * pw[n - i]) + s[i] * pw[n - i];
        hashv s2 = t[i + 1] - t[i + 1 + n] * pw[n];
        if (s1 == s2)
        {
            for (int j = n - 1; j >= 0; j --)
                printf("%c", tt[i + 1 + j]);
            puts("");
            printf("%d\n", i);
            return 0;
        }
    }
    puts("-1");
}
posted @ 2023-01-08 00:02  DM11  阅读(175)  评论(0编辑  收藏  举报