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");
}