AtCoder Beginner Contest 284
A - Sequence of Strings
Problem Statement
题意:给你n个字符串,让你倒序输出
Solution
#include<bits/stdc++.h>
using namespace std;
const int N = 20;
string s[N];
int main()
{
int n;
cin>>n;
for(int i = 1;i<=n;i++)
cin>>s[i];
for(int i = n;i>=1;i--)
cout<<s[i]<<endl;
return 0;
}
B - Multi Test Casescenter
Problem Statement
题意:给你一个长度为n的序列,统计奇数出现次数
Solution
#include<bits/stdc++.h>
using namespace std;
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
int ans = 0;
for(int i = 1;i<=n;i++)
{
int x;
cin>>x;
if(x&1)ans++;
}
cout<<ans<<endl;
}
return 0;
}
C - Count Connected Components
Problem Statement
题意:给你一个简单无向图,\(N\)个点,\(M\)条边,找有多少个连通块
Solution
题解:并查集裸题,找有多少个连通块
#include<bits/stdc++.h>
using namespace std;
const int N = 110;
int n,m,fa[N];
set<int>s;
int find(int x)
{
if(x==fa[x])return x;
return fa[x] = find(fa[x]);
}
int main()
{
int n,m;
cin>>n>>m;
for(int i = 1;i<=n;i++)fa[i] = i;
for(int i = 1;i<=m;i++)
{
int x,y;
cin>>x>>y;
int fx = find(x),fy = find(y);
if(fx!=fy)
fa[fx] = fy;
}
for(int i = 1;i<=n;i++)
fa[i] = find(fa[i]);
for(int i = 1;i<=n;i++)
s.insert(fa[i]);
cout<<s.size()<<endl;
return 0;
}
D - Happy New Year 2023
Problem Statement
题意:给你一个正整数\(N\),\(N=p^2 \times q\) ,其中\(p,q\)为两个不同的素数,现在需要找出这个\(p\)和\(q\)。
Solution
题解:
因为发现\(N\)的范围是\(10^{18}\),直接写肯定\(TLE\)。
我们发现\(min(p,q)<\sqrt[3]{N}\),因为当\(p=q\)时,\(min(p,q)\)有最大值等于\(\sqrt[3]{N}\)
又因为题目给的\(N\)一定保证了\(p\)和\(q\)的存在性,且都为质数,所以\(N\)不存在其他因子。
我们只需要找到其中一个去求另一个就行了。时间复杂度O(\(\sqrt[3]{N}\))。
#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
for(int i = 2;i<sqrt(n)+1;i++)
{
if(n%(i*i)==0)
{
cout<<i<<" "<<n/(i*i)<<endl;
break;
}
else if(n%i==0)
{
cout<<(int)sqrt(n/i)<<" "<<i<<endl;
break;
}
}
}
return 0;
}
E - Count Simple Paths
Problem Statement
题意:给你一个简单无向图,\(N\)个点\(M\)条边,求从\(1\)出发简单路径的数量\(K\)。
简单路:路径中不出现重复的点。
题目保证\(ans = min(K,10^6)\)
- \(1<=N<=2\times10^5\)
- \(0 \leq M \leq \min \left(2 \times 10^5, \frac{N(N-1)}{2}\right)\)
Solution
题解:求路径条数?一眼\(dfs\),但是会不会\(TLE\)嘞,不会,因为当\(K>10^6\)时候输出\(10^6\),那就是一个裸的\(dfs\).
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 2e5+10;
vector<int>edge[N];
int ans = 0;
bool vis[N];
void dfs(int x)
{
if(ans>=1e6)
return;
ans++;
for(auto y:edge[x])
{
if(!vis[y])
{
vis[y] = true;
dfs(y);
vis[y] = false;
if(ans>=1e6)
return;
}
}
}
signed main()
{
int n,m;
cin>>n>>m;
for(int i = 1;i<=m;i++)
{
int x,y;
cin>>x>>y;
edge[x].push_back(y);
edge[y].push_back(x);
}
vis[1] = true;
dfs(1);
cout<<ans<<endl;
return 0;
}
F - ABCBAC
Problem Statement
题意:给你一个长度为\(N\)的字符串,
定义\(fi(S)\):
-
取\(S\)的前\(i\)个
-
翻转字符串\(S\)
-
取后面的\((N-i)\)个
按照以上顺序拼接起来
题目告诉你原串的长度\(N\),和操作完之后的字符串\(T\),让你求原串\(S\).
Solution
题解:
以样例为例:
3
abcbac
答案是
abc
2
我们观察发现\(pre1\)和\(suf1\)是对称的,\(suf2\)和\(pre2\)是对称的
即\(pre1+pre2 = reverse(suf2+suf1)\)
由此,我们只需要枚举分割点\(i\),直接暴力判肯定不行,询问次数很多肯定T。为了快速进行字符串的匹配,我们想到用哈希。
法一:把区间分为如图四段:\([1,i],[i+1,n],[n+1,n+i],[i+n+1,2n]\)
只要pre1的哈希值等于suf1的,suf2的哈希值等于pre2的(注意后一半我们反过来了,写的时候注意)那就是答案。
#include<bits/stdc++.h>
using namespace std;
typedef pair<long long, long long> pll;
struct DoubleStringHash
{
vector<long long> h1, h2, w1, w2;
long long base1 = 131, base2 = 13331;
long long p1 = 1e9 + 7, p2 = 1e9 + 9;
void init(string s) {
int len = s.size();
s = " " + s;
h1.resize(len + 1), w1.resize(len + 1);
h2.resize(len + 1), w2.resize(len + 1);
h1[0] = 0, w1[0] = 1;
h2[0] = 0, w2[0] = 1;
for(int i = 1; i <= len; i++) {
h1[i] = (h1[i - 1] * base1 + s[i]) % p1, w1[i] = w1[i - 1] * base1 % p1;
h2[i] = (h2[i - 1] * base2 + s[i]) % p2, w2[i] = w2[i - 1] * base2 % p2;
}
}
pll get(int l, int r) {
return {(h1[r] - h1[l - 1] * w1[r - l + 1] % p1 + p1) % p1, (h2[r] - h2[l - 1] * w2[r - l + 1] % p2 + p2) % p2};
}
}ha,ha2;
int main()
{
int n; cin>>n;
string s;
cin>>s;
string t = s;
reverse(t.begin(), t.end());
ha.init(s);
ha2.init(t);
s = "?"+s;
for(int i = 0;i<=n;i++)
{
if(ha.get(1,i)==ha2.get(n-i+1,n)&&
ha.get(i+1,n)==ha2.get(1,n-i))//因为reverse了,所以后半部分翻转到前面,所以区间是这样
{
cout <<s.substr(1, i)<<s.substr(n+i+1,n-i)<<endl;
cout<<i<<endl;
return 0;
}
}
cout<<-1<<endl;
return 0;
}
法二:把区间分为三段,\([1,i]+[i+n+1,2n]和[i+1,n+i]\)
#include <bits/stdc++.h>
using namespace std;
#define int __int128
const int N = 2e6+10;
int n;
int h[N],p[N],H[N];
const int mod = 1e14+7;
string s;
inline int read() {
int s = 0, w = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-')
w = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
s = (s << 3) + (s << 1) + (c ^ 48);
c = getchar();
}
return s * w;
}
inline void write(int x) {
if (x < 0) {
putchar('-');
x = -x;
}
if (x >= 10)
write(x / 10);
putchar(x % 10 + '0');
return;
}
inline int calc1(int l, int r) {
return (h[r] - h[l - 1] * p[r - l + 1] % mod + mod) % mod;
}
inline int calc2(int l, int r) {
return (H[l] - H[r + 1] * p[r - l + 1] % mod + mod) % mod;
}
signed main()
{
n = read();
cin>>s;
s = "?"+s;
p[0] = 1;
for(int i = 1;i<=(n<<1);i++)
{
p[i] = p[i-1]*131;
h[i] = h[i-1]*131+s[i];
p[i]%=mod,h[i]%=mod;
}
for(int i = (n<<1);i>=0;i--)
H[i] = H[i+1]*131+s[i],H[i]%=mod;
for(int i = 0;i<=n;i++)
{
int x = ((h[i]*p[n-i])%mod+calc1(n+i+1,n*2)+mod)%mod;
int y = calc2(i+1,i+n);
if(x==y)
{
cout << s.substr(1, i) << s.substr(n + i + 1, n - i) << endl;
write(i);
return 0;
}
}
cout<<-1<<endl;
return 0;
}