EPIC Institute of Technology Round Summer 2025 (Codeforces Round 1036, Div. 1 + Div. 2)(A~E)

期末周结束回归第二场,第一场(昨天)才做了三题,于是就没打算写了

A.Deranged Deletions

思路:题目问你是否能找到一个子数组,使得sort后,每个位置和原位置不同。显然只要存在一个逆序对即可有解,暴力即可(n很小),也可以用二分

#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const ll N = 5e5 + 45;
const ll mod = 998244353;
ll ksm(ll x, ll y) {
    ll ans = 1;
    while (y) {
        if (y & 1)ans = ans * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return ans % mod;
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    ll t;
    cin>>t;
    while(t--){
        ll n;
        cin>>n;
        vector<ll>a(n+2,0);
        vector<ll>b(n+2,0);
        for(ll i=1;i<=n;i++)cin>>a[i];
        b=a;
        sort(b.begin()+1,b.begin()+1+n);
        if(b==a)cout<<"NO"<<endl;
        else {
            cout<<"YES"<<endl;
            cout<<2<<endl;
            set<ll>d;
            for(ll i=1;i<=n;i++){
                auto j=d.upper_bound(a[i]);
                if(j!=d.end()){
                    cout<<(*j)<<" "<<a[i]<<endl;
                    break;
                }
                 d.insert(a[i]);
            }
        }
    }
}   

B.Minimise Sum

思路:分类讨论下,记住a[1]必拿。如果a[1]<a[2],那么可以假定a[3]放到了a[2],于是两个a[1]即为答案;如果a[1]=a[2],那么就把a[2]加到a[1]即可;如果a[1]>a[2],正常是a[1]+a[2],由于a[1]必拿,所以a[2]不要变即可,那么a[2]加到a[1]即可。

#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const ll N = 5e5 + 45;
const ll mod = 998244353;
ll ksm(ll x, ll y) {
    ll ans = 1;
    while (y) {
        if (y & 1)ans = ans * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return ans % mod;
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    ll t;
    cin>>t;
    while(t--){
        ll n;
        cin>>n;
        vector<ll>a(n+2);
        for(ll i=1;i<=n;i++)cin>>a[i];
        if(a[1]==a[2]){
            cout<<2*a[1]<<endl;
        }
        else if(a[1]>a[2]){
            cout<<a[1]+a[2]<<endl;
        }
        else {
            cout<<a[1]*2<<endl;
        }
    }
}   
 

C.Subset Multiplication

思路:从后往前找。只关注a[i]%a[i-1]!=0,此时必定是a[i-1]乘zu以了x而a[i]没乘x,那么此时把两者的公约数求以下,寓意最大重合部分(a[i-1]最大可能值),随后把a[i-1]/公约数,得出一个小于等于x且是x的倍数的可能数,显然答案可以是所有这种数的lcm(最小公倍数)了。

#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const ll N = 5e5 + 45;
const ll mod = 998244353;
ll ksm(ll x, ll y) {
    ll ans = 1;
    while (y) {
        if (y & 1)ans = ans * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return ans % mod;
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    ll t;
    cin>>t;
    while(t--){
        ll n;
        cin>>n;
        vector<ll>a(n+2);
        for(ll i=1;i<=n;i++)cin>>a[i];
        ll ans=1;
        vector<ll>b;
        for(ll i=n-1;i>=1;i--){
            if(a[i+1]%a[i]==0)continue;
            else {
                b.push_back(a[i]/__gcd(a[i],a[i+1]));
            }
        }
        if(b.size()==0)cout<<91<<endl;
        else {
            ll ans=0;
            for(auto j:b){
                if(ans==0)ans=j;
                else {
                    ll u=__gcd(ans,j);
                    ans=ans*j/u;
                }
            }
            cout<<ans<<endl;
        }
    }
}   

D. Make a Palindrome

思路:我们先思考会,可以发现只要是全局数大于等于第k个的数都能删除(有些有个数限制)。那么我们可能把能全删除的删除,好了现在只剩下部分有个数限制的删除。由于只对一种数删除,那我们直接强构造回文串即可,每次不符合就考虑把能删除的数删除,并把conut--,最后得出一个数组,检测下是否回文即可

#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const ll N = 5e5 + 45;
const ll mod = 998244353;
ll ksm(ll x, ll y) {
    ll ans = 1;
    while (y) {
        if (y & 1)ans = ans * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return ans % mod;
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    ll t;
    cin>>t;
    while(t--){
        ll n,k;
        cin>>n>>k;
        vector<ll>a(n+2),b(n+2);
        for(ll i=1;i<=n;i++)cin>>a[i];
        b=a;
        sort(b.begin()+1,b.begin()+1+n);
        vector<bool>vis(n+2,0),wz(n+2,0);
        ll kk=0;
        ll cnt=0;
        for(ll i=k;i<=n;i++){
            if(kk==0)kk=b[i],cnt++;
            else if(kk==b[i])cnt++;
            else vis[b[i]]=1;
        }
        ll len=0;
        for(ll i=1;i<=n;i++){
            if(vis[a[i]])continue;
            else b[++len]=a[i];
        }
        ll l=1,r=len;
        while(1){
            if(cnt==0||l>=r)break;
            else {
                if(b[l]==b[r])l++,r--;
                else {
                    if(kk==b[l])cnt--,wz[l]=1,l++;
                    else if(kk==b[r])cnt--,wz[r]=1,r--;
                    else break;
                }
            }
        }
        ll relen=0;
        for(ll i=1;i<=len;i++){
            if(wz[i])continue;
            b[++relen]=b[i];
        }
        bool flag=0;
        l=1,r=relen;
        while(l<=r){
            if(b[l]==b[r])l++,r--;
            else {
                flag=1;
                break;
            }
        }
        cout<<(flag==0?"YES":"NO")<<endl;
    }
}   
 

E.Make it Zero

思路:看了了个最大操作次数17,于是一直想二分,后面发现只要满足约束条件最大次数就是2.首先数组和必须为偶数,不然不可能最后变成0,其次就是最大值小于等于其他数之和(保证最大数能变为0)。只要上述两个条件满足,即可有解。第一次,我们直接选能分成两个部分的最小值最大的位置(找到max(min(pre[i-1],pre[n]-pre[i-1]))),随后直接先把小的处理,然后处理大的(如果两个部分值相等,显然只要一次),随后可以直接强构造大值区间两部分先相等,然后把剩下要减少的值平均分给两个区间,这样即可得到答案。

#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
using namespace std;
const ll N = 5e5 + 45;
const ll mod = 998244353;
ll ksm(ll x, ll y) {
    ll ans = 1;
    while (y) {
        if (y & 1)ans = ans * x % mod;
        x = x * x % mod;
        y >>= 1;
    }
    return ans % mod;
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    ll t;
    cin>>t;
    while(t--){
        ll n;
        cin>>n;
        vector<ll>a(n+2);
        ll sum=0;
        for(ll i=1;i<=n;i++)cin>>a[i],sum+=a[i];
        if(sum&1)cout<<-1<<endl;
        else {
            ll flag=0;
            for(ll i=1;i<=n;i++){
                if(a[i]>sum-a[i]){
                    flag=1;
                }
            }
            if(flag)cout<<-1<<endl;
            else {
                vector<ll>pre(n+4,0),del(n+4,0);
                vector<ll>an[22];
                for(ll i=1;i<=20;i++)an[i].resize(n+2,0);
                // cout<<an[2][1]<<endl;
                // return 0;
                ll cs=0;
                while(1){
                    for(ll i=1;i<=n;i++){
                        pre[i]=pre[i-1]+a[i];
                        del[i]=0;
                    }
                    if(pre[n]==0){
                        break;
                    }
                    cs++;
                    ll maxn=0;
                    ll wz=0;
                    for(ll i=1;i<=n;i++){//实际为1~i-1,i~n
                        ll u=min(pre[i-1],pre[n]-pre[i-1]);
                        if(maxn<u){
                            maxn=u;
                            wz=i;
                        }
                    }
                    ll l,r;
                    ll sum=maxn;
                    ll k=pre[n]-maxn;
                    if(maxn==pre[n]-maxn){
                        for(ll i=1;i<=n;i++)an[cs][i]=a[i];
                        break;
                    }
                    if(pre[wz-1]<=pre[n]-pre[wz-1]){
                        for(ll i=1;i<=wz-1;i++)an[cs][i]=0,a[i]=0;
                        l=wz,r=n;
                    }
                    else {
                        for(ll i=wz;i<=n;i++)an[cs][i]=0,a[i]=0;
                        l=1,r=wz-1;
                    }
                    for(ll i=l;i<=r;i++){
                        ll z1=pre[i]-pre[l-1];
                        ll z2=pre[r]-pre[i];
                        if(z1<=z2&&z1+maxn>=z2){
                            ll u=z2-z1;
                            maxn=maxn-u;
                            for(ll j=i+1;j<=r;j++){
                                if(a[j]>=u){
                                    a[j]-=u;
                                    break;
                                }
                                else u-=a[j],a[j]=0;
                            }
                            ll z=maxn/2;
                            for(ll j=l;j<=i;j++){
                                if(z==0)break;
                                if(z>=a[j])z-=a[j],a[j]=0;
                                else a[j]-=z,z=0;
                            }
                            z=maxn/2;
                            for(ll j=i+1;j<=r;j++){
                                if(z==0)break;
                                if(z>=a[j])z-=a[j],a[j]=0;
                                else a[j]-=z,z=0;
                            }
                            break;
                        }
                        else if(z1>=z2&&z2+maxn>=z1){
                             ll u=z1-z2;
                              maxn-=u;
                                for(ll j=l;j<=i;j++){
                                if(a[j]>=u){
                                    a[j]-=u;
                                    break;
                                }
                                else u-=a[j],a[j]=0;
                            }
                             ll z=maxn/2;
                            for(ll j=l;j<=i;j++){
                                if(z==0)break;
                                if(z>=a[j])z-=a[j],a[j]=0;
                                else a[j]-=z,z=0;
                            }
                            z=maxn/2;
                            for(ll j=i+1;j<=r;j++){
                                if(z==0)break;
                                if(z>=a[j])z-=a[j],a[j]=0;
                                else a[j]-=z,z=0;
                            }
                            break;
                        }
                    }
                    for(ll i=1;i<=n;i++)an[cs][i]=pre[i]-pre[i-1]-a[i];
                }
                cout<<cs<<endl;
                for(ll i=1;i<=cs;i++){
                    for(ll j=1;j<=n;j++)cout<<an[i][j]<<" ";
                    cout<<endl;
                }
            }
        }
    }
}


posted @ 2025-07-07 01:46  长皆  阅读(77)  评论(0)    收藏  举报