Educational Codeforces Round 102 (Rated for Div. 2) A-D题解

A.Replacing Elements

题解:
如果需要替换就使用整个序列中最小的两个元素去做替换,如果替换后仍不满足直接Say NO
AC代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<stack>
#include<queue>
#include<bitset>
#include<list>
#define ll long long
#define INF 1e12
#define inf -1e12
#define PII pair<int,int>
#define ull unsigned long long
#define ios std :: ios :: sync_with_stdio(false)

using namespace std;

const int maxn = 1e5 + 10;
int a[maxn] = {};

int main() {
    ios;
    int t;
    cin >> t;
    while (t--) {
        int n, d, m1, m2;
        cin >> n >> d;
        for (int i = 1; i <= n; i++) cin >> a[i];
        sort(a + 1, a + 1 + n);
        m1 = a[1];
        m2 = a[2];
        bool flag = 1;
        for (int i = 1; i <= n; i++) {
            if (a[i] > d) {
                if (m1 + m2 > d) {
                    flag = 0;
                    break;
                }
            }
        }
        if (flag) cout << "YES" << endl;
        else cout << "NO" << endl;
    }
    return 0;
}

B.String LCM

题解:
这个题目的数据量很小的,可以直接构建两个 L c m ( s , t ) Lcm(s,t) Lcm(s,t)长度的字符串然后逐位比较即可,最长不会超过500的一个字符串。
AC代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<stack>
#include<queue>
#include<bitset>
#include<list>
#define ll long long
#define INF 1e12
#define inf -1e12
#define PII pair<int,int>
#define ull unsigned long long
#define ios std :: ios :: sync_with_stdio(false)

using namespace std;

int gcd(int a,int b)
{
    if(b == 0) return a;
    else return gcd(b,a % b);
}

int lcm(int a,int b)
{
    return a / gcd(a,b) * b;
}

int main()
{
    ios;
    int t;
    cin >> t;
    while(t--) {
        string s,t,s1,s2;
        cin >> s >> t;
        int lens = s.length(),lent = t.length();
        int len_max = lcm(max(lens,lent),min(lens,lent));
        int ks = len_max / lens,kt = len_max / lent;
        for(int i = 1;i <= ks;i++) s1 += s;
        for(int i = 1;i <= kt;i++) s2 += t;
        if(s1 == s2) cout << s1 << endl;
        else cout << -1 << endl;
    }
    return 0;
}

C.No More Inversions

题解:
OK一道非常玄学的题目
这个题目貌似可以暴力,但是我个人感觉正解还是数学。
我们先给出结论:我们发现,不管P如何构成,最后你得到的b序列的逆序对是和a相等的
给出证明:
首先我们对于a序列我们知道它的组成 1 , 2 , 3 , . . . . . . k , k − 1 , k − 2...... k − ( n − k ) 1,2,3,......k,k - 1,k - 2......k - (n - k) 1,2,3,......k,k1,k2......k(nk)
那么对应到b序列上是: p [ a 1 ] , p [ a 2 ] , . . . . . . p [ a k ] , p [ a k − 1 ] , . . . . . . p [ a k − ( n − k ) ] p[a_{1}],p[a_{2}],......p[a_{k}],p[a_{k - 1}],......p[a_{k - (n - k)}] p[a1],p[a2],......p[ak],p[ak1],......p[ak(nk)]
我们可以得出,对于a,b两个序列,有 2 n − 2 k + 1 2n-2k+1 2n2k+1个数据是中心对称分布的,我们暂且记为 s u m sum sum
那么对于a序列,他的逆序对数的来源就是这 s u m sum sum个数。我们注意到,对于小于 k − ( n − k ) k - (n - k) k(nk)的数,他其实是没有逆序对的,那么我们从左向右考虑每一个大于等于 k − ( n − k ) k - (n - k) k(nk)的数: . . . k − ( n − k ) , . . . k . . . , k − ( n − k ) ...k - (n - k),...k...,k - (n - k) ...k(nk),...k...,k(nk)
从左向右,每个数的逆序对数分别为:0,1,2,3…(n - k),这里要注意的是我们只计算到了k,而在整个序列中,k的数量为1,其他的数据都需要乘2,于是我们可以得到这样的式子: I n v e r s i o n ( a ) = ( n − k ) ∗ ( n − k + 1 ) 2 − ( n − k ) Inversion(a) = \frac{(n - k) * (n - k + 1)}{2} - (n - k) Inversion(a)=2(nk)(nk+1)(nk)最后得到的答案: I n v e r s i o n ( a ) = ( n − k ) 2 Inversion(a) = (n - k)^2 Inversion(a)=(nk)2
下面我们来看b序列: 我们同样使用类似的方法分析,对于我们经过p序列构成的b序列,我们同样先考虑中心对称的部分:我们记为 b 1 , b 2 , b 3 , . . . . , b n − k + 1 , . . . b 1 b_{1},b_{2},b_{3},....,b_{n - k + 1},...b_{1} b1,b2,b3,....,bnk+1,...b1
我们对于这个序列中的第一大元素:假设他的位置是i,那么和他对称的位置就是 s u m − i + 1 sum - i + 1 sumi+1这样i上的元素产生的逆序对数为: I n v e r s i o n ( i ) = s u m − i − 1 + i − 1 = s u m − 2 Inversion(i) = sum - i - 1 + i - 1 = sum - 2 Inversion(i)=sumi1+i1=sum2和值的位置没有关系!我们再看第二大的元素: I n v e r s i o n ( j ) = s u m − 4 Inversion(j) = sum - 4 Inversion(j)=sum4其实就是扣掉了最大值的两个位置,可以证明不管这两个值的分布,这一性质都是成立的。这里需要注意一点,我们其实没有考虑 b n − k + 1 b_{n - k + 1} bnk+1的元素,因为在计算其他满足对称关系的逆序对数目的时候其实已经把他自己包含进去了。我们得到这个答案是 I n v e r s i o n ( b ) = ∑ 1 ≤ i ≤ n − k ( s u m − 2 i ) Inversion(b) = \sum_{\mathclap{1\le i\le n - k}} (sum - 2i) Inversion(b)=1ink(sum2i)
这里也可以看出我们只考虑了前面 n − k n - k nk个数
所以我们可以惊讶地发现:b序列的逆序对和p其实没有什么直接关系!那既然要求我们b序列的字典尽可能大,那直接从大往小取就好了!前面的不需要变化。
AC代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<stack>
#include<queue>
#include<bitset>
#include<list>
#define ll long long
#define INF 1e12
#define inf -1e12
#define PII pair<int,int>
#define ull unsigned long long
#define ios std :: ios :: sync_with_stdio(false)

using namespace std;

int main()
{
    ios;
    int t;
    cin >> t;
    while(t--){
        int n,k;
        cin >> n >> k;
        int sum = 2 * (n - k) + 1;
        for(int i = 1;i <= n - sum;i++) cout << i << ' ';
        for(int i = k;i > n - sum + 1;i--) cout << i << ' ';
        cout << n - sum + 1 << endl;
    }
    return 0;
}

D.Program

题解:
首先这个题目是一个+1累计,所以我们只需要找他的最大最小值相减+1就是最后的答案。
去掉 [ L , R ] [L,R] [L,R]的部分其实就是只执行 [ 1 , L − 1 ] [1,L-1] [1,L1] [ R + 1 , L e n ] [R + 1,Len] [R+1,Len]的操作。我们可以先维护一下每一处的前后缀最大最小值,在删去 [ L , R ] [L,R] [L,R]的区间后,我们其实可以得出 [ R + 1 , L e n ] [R + 1,Len] [R+1,Len]这一段的可增最大值和可减最大值,然后我们只需要考虑这个变化对于 L − 1 L - 1 L1位置的最大最小值影响即可,然后只需要比较他们和 L − 1 L - 1 L1的前缀最大最小值就可以得到答案,因为删除区间后变换是从 L − 1 L - 1 L1的元素开始的!
AC代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
#include<vector>
#include<map>
#include<stack>
#include<queue>
#include<bitset>
#include<list>
#include<limits.h>
#define ll long long
#define INF 1e12
#define inf -1e12
#define PII pair<int,int>
#define ull unsigned long long
#define ios std :: ios :: sync_with_stdio(false)

using namespace std;

const int maxn = 2e5 + 19;

int pmax[maxn],pmin[maxn],lmax[maxn],lmin[maxn],a[maxn];
int t, m, n, l, r;
string s;

void solve()
{
    int len = s.length(),x = 0;
    s = "#" + s;

    for(int i = 1;i <= len;i++){ //记录每一步的x的值
        if(s[i] == '+') x ++;
        else x --;
        a[i] = x;
    }

    pmax[0] = pmin[0] = 0;
    for(int i = 1;i <= len;i++){ //前缀最大最小值
        pmax[i] = max(pmax[i - 1], a[i]);
        pmin[i] = min(pmin[i - 1], a[i]);
    }

    lmax[len] = lmin[len] = a[len];
    for(int i = len - 1;i >= 1;i--){ //后缀最大最小值
        lmax[i] = max(lmax[i + 1], a[i]);
        lmin[i] = min(lmin[i + 1], a[i]);
    }

    while(m--){
        cin >> l >> r;
        int ans = 0;
        int pmaxx = pmax[l - 1],pminn = pmin[l - 1];
        int lmaxx = lmax[r + 1],lminn = lmin[r + 1];
        if(r + 1 > len) ans = pmaxx - pminn + 1;
        else {
            int up = lmaxx - a[r],down = a[r] - lminn;
            int mx = up + a[l - 1],mn = a[l - 1] - down;
            mx = max(mx,pmaxx);mn = min(mn,pminn);
            ans = mx - mn + 1;
        }
        cout << ans << endl;
    }
    return ;
}

int main()
{
    ios;
    cin >> t;
    while(t--){
        cin >> n >> m;
        cin >> s;
        for(int i = 1;i <= m;i++) solve();
    }
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CUCKyrie

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值