Educational Codeforces Round 17 ACD
A. k-th divisor(暴力)
链接
题意:给出n和k,求出n的第k个因子
n
≤
1
0
15
,
k
≤
1
0
9
n \le 10^{15},k \le 10^9
n≤1015,k≤109
思路:直接
n
\sqrt{n}
n的因数分解,特判1
#include<bits/stdc++.h>
using namespace std;
#define int long long
signed main()
{
int n, k;
cin >> n >> k;
if (n == 1) {if (k == 1) cout << 1; else cout << -1; return 0;}
vector<int> vec;
for (int i = 1; i * i <= n; i++) {
if (i * i == n && n % i == 0) {vec.push_back(i); break;}
if (n % i == 0) vec.push_back(i), vec.push_back(n / i);
}
sort(vec.begin(), vec.end());
if (k > vec.size()) {cout << -1;return 0;}
cout <<vec[k - 1];
return 0;
}
C. Two strings
链接
题意:给出字符串a和b,需要从b中删除一段连续的字符,使得b是a的子序列,要求最小化删除数量,求完成删除的b
思路:因为要求完成删除的b,我们可以求一个b前缀对于a字子序列和b后缀对于a的子序列,前缀数组
l
[
i
]
l[i]
l[i]的含义是在a在
i
i
i位置可以包含a的子序列的长度。然后因为要是的子序列并且最短,我们遍历a的前缀长度i,那么对于后缀,他包含的b需要比前缀的大,所以在遍历的时候用一个二分,就可以确定删除的区间,更新一个最小值就行
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N = 1e5+10;
int l[N], r[N];
char a[N], b[N];
signed main()
{
cin >> (a + 1) >> (b + 1);
int idx = 1;
int lena = strlen(a + 1), lenb = strlen(b + 1);
for (int i = 1 ; i <= lena; i++) {
if (b[idx] == a[i]) {idx++;}
l[i] = idx - 1;
}
idx = lenb;
for (int i = lena; i >= 1; i--) {
if (b[idx] == a[i]) {idx--;}
r[i] = idx + 1;
}
r[lena + 1] = lenb + 1;
int ansr = 0, ansl = 0, minn = 1e9;
for (int i = 0; i < lena; i++) {
int R = upper_bound(r + i + 1, r + 1 + lena, l[i]) - r;
R = r[R];
int L = l[i];
if (R - L - 1 < minn) {
ansr = R; ansl = L; minn = R - L - 1;
}
}
int R = lenb + 1;
int L = l[lena];
if(R - L - 1 < minn) {
ansl = L;
ansr = R;
}
for (int i = 1; i <= ansl; i++) cout << b[i];
for (int i = ansr; i <= lenb; i++) cout << b[i];
if (ansr > lenb && ansl < 1) {cout << '-';}
return 0;
}
D. Maximum path(状态dp,推结论)
链接
题意:给出一个
3
∗
n
3*n
3∗n的矩阵,可以往上下左右走,要求从
(
1
,
1
)
(1,1)
(1,1)到
(
3
,
n
)
(3,n)
(3,n)路径权值最小
思路:最麻烦的是往左走,但是我们可以发现,任何往左走多步的状况都可以被只往左走一步或者一直上下右走替代,分成奇偶讨论,不方便画图,看情况补图把,然后接下来就是枚举状态了,我总共写了5种状态,分别是最后一步走在
(
1
,
i
)
,
(
2
,
i
)
,
(
3
,
i
)
(1,i),(2,i),(3,i)
(1,i),(2,i),(3,i),然后还有两个左走的情况,因为左走最后回到的地方一定是
(
1
,
i
)
,
(
3
,
i
)
(1,i),(3,i)
(1,i),(3,i),但是这时候会产生两列的代价,因为涉及到往回走,所以在算两种情况,根据5种情况凑一下dp
图片来源洛谷
#include<bits/stdc++.h>
using namespace std;
#define int long long
int dp[1000010][5], a[4][1000010];
signed main()
{
int n;
cin >> n;
for (int i = 1; i <= 3; i++) {
for (int j = 1; j <= n; j++) cin >> a[i][j];
}
dp[1][0] = a[1][1];
dp[1][1] = a[1][1] + a[2][1];
dp[1][2] = dp[1][3] = dp[1][1] + a[3][1];
dp[1][4] = -0x3f3f3f3f3f3f3f3f;
for(int i = 2; i <= n; i++) {
dp[i][0] = max({dp[i - 1][0] + a[1][i], dp[i - 1][1] + a[1][i] + a[2][i], dp[i - 1][2] + a[1][i] + a[2][i] + a[3][i], dp[i - 1][4] + a[1][i] + a[2][i] + a[3][i]});
dp[i][1] = max({dp[i - 1][0] + a[1][i] + a[2][i], dp[i - 1][1] + a[2][i], dp[i - 1][2] + a[2][i] + a[3][i]});
dp[i][2] = max({dp[i - 1][0] + a[1][i] + a[2][i] + a[3][i], dp[i - 1][1] + a[2][i] + a[3][i], dp[i - 1][2] + a[3][i], dp[i - 1][3] + a[1][i] + a[2][i] + a[3][i]});
dp[i][3] = max(dp[i - 1][0] + a[1][i] + a[2][i] + a[3][i], dp[i - 1][3] + a[1][i] + a[2][i] + a[3][i]);
dp[i][4] = max(dp[i - 1][2] + a[1][i] + a[2][i] + a[3][i], dp[i - 1][4] + a[1][i] + a[2][i] + a[3][i]);
}
cout << max({dp[n][2], dp[n][3]});
return 0;
}