Educational Codeforces Round 17 ACD

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 n1015,k109
思路:直接 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 3n的矩阵,可以往上下左右走,要求从 ( 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值