最坐牢的一次div3啊QAQ
A:
给定长度为 n 的字符串 x 和长度为 m (n⋅m≤25) 的字符串 s(由小写拉丁字母组成),您可以对字符串 x 应用任意数量的运算。
在一项操作中,您将 x 的当前值附加到字符串 x 的末尾。请注意,此后 x 的值将会改变。
例如,如果x=“aba”,则应用操作后,x将更改为:“aba”→→“abaaba”→→“abaabaabaaba”。
经过多少次最少操作后,s 将作为子字符串出现在 x 中?字符串的子字符串被定义为它的连续段。
输入
输入的第一行包含一个整数 t (1≤t≤1e4) - 测试用例的数量。
每个测试用例的第一行包含两个数字 n 和 m (1≤n⋅m≤25) - 分别是字符串 x 和 s 的长度。
每个测试用例的第二行包含长度为 n 的字符串 x。
每个测试用例的第三行包含长度为 m 的字符串 s。
输出
对于每个测试用例,输出一个数字 - 最小 操作数,之后 s 将作为子字符串出现在 x 中。如果不可能,则输出 −1。
这道题其实就是复制字符串a再拼接,直接再寻找b就行了
然后我就写出了这么一串:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e9 + 5;
void init()
{
}
void solve()
{
int x, y; cin >> x >> y;
string a, b; cin >> a >> b;
int n = 0;
int flag = 0;
for(int i = 0; i < y; ++i)
{
if(a.find(b) < a.size())
{
flag = 1;
break;
}
++n;
a += a;
}
if(flag) cout << n << '\n';
else cout << -1 << '\n';
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int _; cin >> _;
init();
while(_--) solve();
return 0;
}
信心满满交上去之后
TLE
因为当最后结果为-1且b的长度很大的时候,循环次数会多,查找运行的时间也会多。
解决这个问题的方法很简单,a + a多出来的无非就是头尾相接的部分,所以当a的长度大于等于b的长度时,此时只要再复制一次a,如果还没找到,那最后结果肯定就是-1。
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e9 + 5;
void init()
{
}
void solve()
{
int x, y; cin >> x >> y;
string a, b; cin >> a >> b;
int n = 0;
int flag = x + y;
int flag2 = 0;
for(int i = 0; i < y; ++i)
{
if(a.find(b) < a.size())
{
flag2 = 1;
break;
}
++n;
if(!(--flag)) break;
if(a.size() > b.size())flag = 1;
a += a;
}
if(flag2) cout << n << '\n';
else cout << -1 << '\n';
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int _; cin >> _;
init();
while(_--) solve();
return 0;
}
但是赛后又发现了这么一个神奇的解法,就是不从这个点出发,直接优化循环次数也是OK的,这个时候就要注意一下数据的大小了,因为字符串长度最多是25,而从a的长度是1,b长度是25的这种最坏情况考虑,就不难发现其实只要循环5次,就一定能满足上面提到的调节,从而找到答案。
代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e9 + 5;
string a, b;
void init()
{
}
void solve()
{
int n, m;
string x, s;
int ans = 0, a = 0, b = 0;
cin >> n >> m;
cin >> x;
cin >> s;
for(int i = 0; i <= 5; ++i)
{
if(x.find(s) != -1)
{
cout << ans << '\n';
return;
}
x += x;
ans++;
}
cout << "-1" << '\n';
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int _; cin >> _;
init();
while(_--) solve();
return 0;
}
B:
从前,酒保德西姆发现了三根细线和一把剪刀。
在一次操作中,Decim 选择任意一个 threadlet,并将其切割成两个 threadlet,其长度为正整数,并且它们的总和等于被切割的 threadlet 的长度。
例如,他可以将长度为 55 的细丝切割为长度为 2 和 3 的细丝,但不能将其切割为长度为 2.5 和 2.5 的细丝,或者长度为 0 和 5 的细丝。 },或长度3和4。
Decim 最多可以执行三个运算。他被允许切割先前切割得到的细线。他能把所有的细线都制成相同长度吗?
输入
第一行包含一个整数 t (1≤t≤1e4) - 测试用例的数量。然后是每个测试用例的描述。
在每个测试用例的一行中,有三个整数 a、b、c (1≤a,b,c≤1e9) - 线程的长度。
输出
对于每个测试用例,如果可以通过执行最多三个操作使所有线程长度相等,则输出“YES”,否则输出“NO”。
您可以在任何情况下输出“YES”和“NO”(例如,字符串“yEs”、“yes”、“Yes”和“YES”将被识别为肯定答案)。
我的想法是这样的:
既然有三段且只有三次切的机会,那么肯定就切不到最小值,从这个角度出发,不难得知,另外两端的长度只能是最小值的2倍,3倍或者4倍,且倍数之和绝对不会超过5;
所以我的代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e9 + 5;
int a[3];
void init()
{
}
void solve()
{
int min = 1e9 + 9;
for(int i = 0; i < 3; ++i)
{
cin >> a[i];
if(min > a[i])
{
min = a[i];
}
}
int n = 0;
for(int i = 0; i < 3; ++i)
{
if(a[i] % min == 0 && a[i] / min != 1) n += a[i] / min;
else if(a[i] % min != 0) n = 6;
}
if(n <= 5) cout << "YES" << '\n';
else cout << "NO" << '\n';
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int _; cin >> _;
init();
while(_--) solve();
return 0;
}
但是这样漏考虑了单个数倍数为最小值5倍的情况,导致WA了。
所以还需要特判一下。
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e9 + 5;
int a[3];
void init()
{
}
void solve()
{
int min = 1e9 + 9;
for(int i = 0; i < 3; ++i)
{
cin >> a[i];
if(min > a[i])
{
min = a[i];
}
}
int n = 0;
for(int i = 0; i < 3; ++i)
{
if(a[i] / min > 4) n = 6;
if(a[i] % min == 0 && a[i] / min != 1) n += a[i] / min;
else if(a[i] % min != 0) n = 6;
}
if(n <= 5) cout << "YES" << '\n';
else cout << "NO" << '\n';
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int _; cin >> _;
init();
while(_--) solve();
return 0;
}
当然还有一种方法可以解,且不容易漏细节。
就是可以从三个数的最大公因数出发,每段长度除以最大公约数再减1就是减该段用的次数,再相加,判断是否小于等于3就可得到该题解。
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 1e9 + 5;
ll a[3];
void init()
{
}
void solve()
{
for(int i = 0; i < 3; ++i) cin >> a[i];
ll g, s = 0;
int n = 0;
g = __gcd(a[0], a[1]);
g = __gcd(g, a[2]);
for(int i = 0; i < 3; ++i)
{
if(a[i] / g > 1)
{
s += a[i] / g;
n++;
}
}
if(s - n <= 3)cout << "YES" << '\n';
else cout << "NO" << '\n';
}
int main()
{
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int _; cin >> _;
init();
while(_--) solve();
return 0;
}
最长的一篇~
属实是坐牢坐的印象深刻。