Educational Codeforces Round 102 ABCD——解题报告

比赛链接:https://codeforces.com/contest/1473

A——Replacing Elements

当数组中的最小值和次小值的和小于等于d时或者数组中每个位置的值都小于等于d时输出YES,否则输出NO。

因为按照贪心的思想我们肯定每次选择这两个位置的值对其他位置进行赋值,所以直接判断就行了。

特判一下一次都不赋值的情况就行了。

#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
    return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
    return a/gcd(a,b)*b;
}
inline int read(){
    int s=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=s*10+ch-'0';
        ch=getchar();
    }
    return s*f;
}
const int N = 1e5+7;
int a[N];
void solve(){
    int n=read(),d=read();
    rp(i,1,n) a[i]=read();
    int f=0;
    rp(i,1,n) if(a[i]>d) f=1;
    sort(a+1,a+1+n);
    if(a[1]+a[2]<=d||!f) puts("YES");
    else puts("NO");
    

}
int main(){
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
    freopen("in.txt", "r", stdin);
    //debug = 1;
#endif
    time_t beg, end;
    //if(debug) beg = clock();

    int T=read();
    while(T--) solve();

    /*
    if(debug) {
        end = clock();
        printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
    }
    */
    return 0;
}

B——String LCM

首先给定两个字符串的长度,那么他的最小公倍数串的长度也就定了,就是这两个字符串长度的最小公倍数。

长度确定了,我们直接分别以这两个字符串为基(即每一轮扩展增加的字符串)进行扩展,扩展到他们长度的最小公倍数。

最后判断一下这两个字符串是否相等就行了,如果相等就输出扩展后的字符串,否则输出-1.

#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
    return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
    return a/gcd(a,b)*b;
}
inline int read(){
    int s=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=s*10+ch-'0';
        ch=getchar();
    }
    return s*f;
}
const int N = 1e5+7;
int a[N];
void solve(){
    string s1,s2;cin>>s1>>s2;
    int len1=s1.size();
    int len2=s2.size();
    int len=len1*len2/__gcd(len1,len2);
    string base1=s1;
    int cur=len1;
    while(cur+len1<=len) base1+=s1,cur+=len1;

    string base2=s2;
    cur=len2;
    while(cur+len2<=len) base2+=s2,cur+=len2;

    // cout<<base1<<" "<<base2<<endl;
    if(base1==base2) cout<<base1<<endl;
    else cout<<-1<<endl;
}
int main(){
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
    freopen("in.txt", "r", stdin);
    //debug = 1;
#endif
    time_t beg, end;
    //if(debug) beg = clock();

    int T=read();
    while(T--) solve();

    /*
    if(debug) {
        end = clock();
        printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
    }
    */
    return 0;
}

C——No More Inversions

这个题题意不是特别好懂,有点绕。

其实就是先给你一个数组a,让你构造一个k置换排列,使得按照这个置换对a数组进行替换后的b数组字典序最大,且b数组的逆序对数小于等于a数组的逆序对数。

大致懂了题意后,这个题就可以勇敢地猜一发了,观察样例可以发现答案就是a数组前面中不对称的那一部分,加上a数组对称的后半部分。

举个例子,当n=6,k=4时,a数组就是{1,2,3,4,3,2},答案就是{1,4,3,2}

其中1不在对称的那部分里面,而{4,3,2}是对称的后半部分(含对称轴)。

至于证明的话:可以参考我队友的详细解释

#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
    return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
    return a/gcd(a,b)*b;
}
inline int read(){
    int s=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=s*10+ch-'0';
        ch=getchar();
    }
    return s*f;
}
const int N = 2e5+7;
int a[N];
void solve(){
    int n=read(),k=read();
    rp(i,1,n){
        if(i<=k) a[i]=i;
        else a[i]=2*k-i;
    }
    int cur=1;
    while(k-cur>=1&&k+cur<=n&&a[k-cur]==a[k+cur]) cur++;
    cur--;
    vector<int> ans;
    rp(i,1,k-cur-1) ans.p_b(i);
    RP(i,k,k-cur) ans.p_b(i);
    int len=ans.size();
    rp(i,0,len-1){
        printf("%d%s",ans[i],i==len-1?"\n":" ");
    }
    // rp(i,1,n) cout<<a[i]<<" ";
    // cout<<endl;
    
}
int main(){
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
    freopen("in.txt", "r", stdin);
    //debug = 1;
#endif
    time_t beg, end;
    //if(debug) beg = clock();

    int T=read();
    while(T--) solve();

    /*
    if(debug) {
        end = clock();
        printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
    }
    */
    return 0;
}

D—— Program

这个题比赛时陷入了误区,当时第一想法是用莫队维护,而且还想到了一个比较巧妙的做法,自己想了想也觉得挺对,然后就开始写+调试了,到比赛完也没有调出来,最后才发现好像莫队维护不了,之前想的那种做法是错的!!!!

第二天重新做了这个题才发现只需要维护一下前缀(后缀)最大(最小)值就行了。

首先可以知道当我们知道一个操作区间后,很容易就能算出在这个操作区间数的种类数量=区间内的最大值-最小值+1。

但是现在让我们忽略这个区间[l,r],这样就不能直接维护了,需要进行转换。

可以得知[1,l-1]不会受到影响,只有[r+1,n]会受到影响,因此只需要在[r+1,n]的初始取值区间内减去受到的影响就行了。

而受到的影响也可以很容易算出来,等于[l,r]区间的+操作数减去-操作数。

因此解法也就得出来了,分别算出[1,l-1]的最大值max1和最小值min1,以及[r+1,n]的最大值max2和最小值min2,答案就是这两个取值区间的并(即max(max1,max2)-min(min1,min2)+1)。

至于怎么维护最大值和最小值,其实就是分别维护前缀(后缀)最大(最小)数组就行了。

也可以用线段树或者ST表。

最后再注意一下边界问题和取0的问题就行了。

#include <bits/stdc++.h>
#define PI atan(1.0)*4
#define rp(i,s,t) for (register int i = (s); i <= (t); i++)
#define RP(i,t,s) for (register int i = (t); i >= (s); i--)
#define sc(x) scanf("%d",&x)
#define scl(x) scanf("%lld",&x)
#define ll long long
#define ull unsigned long long
#define mst(a,b) memset(a,b,sizeof(a))
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define pii pair<int,int>
#define pll pair<ll,ll>
#define pil pair<int,ll>
#define m_p make_pair
#define p_b push_back
#define ins insert
#define era erase
#define INF 0x3f3f3f3f
#define LINF 0x3f3f3f3f3f3f3f3f
#define dg if(debug)
#define outval(a) cout << "Debuging...|" << #a << ": " << a << "\n";
using namespace std;
int debug = 0;
ll gcd(ll a,ll b){
    return b?gcd(b,a%b):a;
}
ll lcm(ll a,ll b){
    return a/gcd(a,b)*b;
}
inline int read(){
    int s=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9'){
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9'){
        s=s*10+ch-'0';
        ch=getchar();
    }
    return s*f;
}
const int N = 1e6+7;
int a[N];
char s[N];
int sum1[N],sum2[N];
int lMin[N],lMax[N];
int rMin[N],rMax[N];
void solve(){
    int n=read(),m=read();
    scanf("%s",s+1);
    rp(i,1,n) sum1[i]=sum2[i]=lMin[i]=lMax[i]=rMin[i]=rMax[i]=0;
    int cur=0;
    rp(i,1,n){
        if(s[i]=='+') cur++,sum1[i]=sum1[i-1]+1,sum2[i]+=sum2[i-1];
        else cur--,sum2[i]=sum2[i-1]+1,sum1[i]+=sum1[i-1];
        a[i]=cur;
    }
    rp(i,1,n){
        lMin[i]=min(lMin[i-1],a[i]);
        lMax[i]=max(lMax[i-1],a[i]);
    }
    rMin[n]=rMax[n]=a[n];
    RP(i,n-1,1){
        rMin[i]=min(rMin[i+1],a[i]);
        rMax[i]=max(rMax[i+1],a[i]);
    }
    rp(i,1,m){
        int l=read(),r=read();
        int delta;
        int l1,r1,l2,r2;
        int ans=0;
        if(r==n){//特判边界问题
            l1=lMin[l-1];
            r1=lMax[l-1];
            ans=r1-l1+1;
            if(l1>0||r1<0) ans++;//特判取0的情况
        }
        else if(l==1){//特判边界问题
            delta=sum1[r]-sum2[r];
            l2=rMin[r+1]-delta;
            r2=rMax[r+1]-delta;
            ans=r2-l2+1;
            if(l2>0||r2<0) ans++;//特判取0的情况
        }
        else{
            delta=(sum1[r]-sum1[l-1])-(sum2[r]-sum2[l-1]);
            l1=lMin[l-1];
            r1=lMax[l-1];
            l2=rMin[r+1]-delta;
            r2=rMax[r+1]-delta;
            ans=max(r2,r1)-min(l2,l1)+1;
            if(min(l2,l1)>0||max(r2,r1)<0) ans++;//特判取0的情况
        }
        cout<<ans<<endl;
    }
}
int main(){
    //ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
#ifdef ONLINE_JUDGE
#else
    freopen("in.txt", "r", stdin);
    //debug = 1;
#endif
    time_t beg, end;
    //if(debug) beg = clock();

    int T=read();
    while(T--) solve();

    /*
    if(debug) {
        end = clock();
        printf("time:%.2fs\n", 1.0 * (end - beg) / CLOCKS_PER_SEC);
    }
    */
    return 0;
}

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值