2024 暑假友谊赛 3

Problem - 977D - Codeforces

原本数组中有一个数,你可以对他进行除三操作(必须被三整除)或者乘2,并将结果存入数组中,将这个数修改为这个结果。现在有一个序列,你需要将他们排序,以便可以通过上述操作得到

数据范围只有100,考虑到情况较少,剪枝dfs就行

#include<bits/stdc++.h>
#define endl '\n'
#define mk make_pair
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 1e5+10;
const int mod = 998244353;
int n,m,k,l,cnt;
int a[105];
map<int,int>v,vx;
vector<int>q;
stack<int>f;
bool ok=0;

void dfs(int x,int s){
    if(ok) return;
    if(s==n){
        ok=1;
        for(auto ed:q){
           cout<<ed<<' ';
        }
        return;
    }
    for(int i=1;i<=n;i++){
        if(ok) return;
        if(v[a[i]]&&a[i]*3==x){
            v[a[i]]--;
            q.push_back(a[i]);
            dfs(a[i],s+1);
            v[a[i]]++;
            q.pop_back();
        }
        if(v[a[i]]&&x*2==a[i]){
            v[a[i]]--;
            q.push_back(a[i]);
            dfs(a[i],s+1);
            v[a[i]]++;
            q.pop_back();
        }
    }
}

void sovle(){
    cin>>n;
    for(int i=1;i<=n;i++) {cin>>a[i];v[a[i]]++;}
    for(int i=1;i<=n;i++){
        if(ok){
            return;
        }
        v[a[i]]--;
        q.push_back(a[i]);
        dfs(a[i],1);
        v[a[i]]++;
        q.pop_back();
        if(ok){
            return;
        }
    }
}

signed main()
{	
    ios::sync_with_stdio(false), cin.tie(0),cout.tie(0); 
    int t = 1;
    //cin>>t;
    while (t--){
        sovle();
    }

    return 0;
}

Problem - 1368D - Codeforces

你可以选择数组中的任意两个数并将他们分别修改为ai & aj和ai | aj,请通过任意次操作后使得数组各个数分别平方之和最大。

我们发现操作的本质就是交换二进制位上的0和1,那么尽量让多的1集中起来一定是最优的

#include<bits/stdc++.h>
#define endl '\n'
#define mk make_pair
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 2e5+10;
const int mod = 998244353;
int n,m,k,l,cnt;
int a[64],b[N];
map<int,int>v;

int qmi(int x,int y){
    int res=1;
    while(y){
        if(y&1) res*=x;
        x*=x;
        y>>=1;
    }return res;
}

void sovle(){
    int u=1;a[0]=u;
    for(int i=1;i<63;i++){
        u*=2;
        a[i]=u;
    }
    cin>>n;
    for(int i=0;i<n;i++){
        cin>>m;
        int cnt=0;
        for(int j=0;j<63;j++){
            if(a[cnt]&m){
                v[cnt]++;
            }
            cnt++;
        }
    }
    for(int i=0;i<n;i++){
        for(int j=0;j<63;j++){
            if(v[j]){
                b[i]+=a[j];
                v[j]--;
            }
        }
    }
    int sum=0;
    for(int i=0;i<n;i++){
        sum+=qmi(b[i],2);
    }cout<<sum<<endl;
}

signed main()
{	
    ios::sync_with_stdio(false), cin.tie(0),cout.tie(0); 
    int t = 1;
    //cin>>t;
    while (t--){
        sovle();
    }

    return 0;
}

D - Derangement (atcoder.jp)

既然只能交换相邻两个,那么如果相邻两个都是ai=i,那么交换一次就能解决两个一定是最优的。

#include<bits/stdc++.h>
#define endl '\n'
#define mk make_pair
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 1e5+10;
int n,m,k,l;
int a[N];
bool b[N];

void sovle(){
    cin>>n;
    for(int i=1;i<=n;i++) cin>>a[i];
    for(int i=1;i<=n;i++){
        if(a[i]==i) b[i]=1;
    }
    for(int i=1;i<=n;i++){
        if(b[i]&&b[i-1]){
            b[i]=b[i-1]=0;
            m++;
        }
    }
    for(int i=1;i<=n;i++) if(b[i]) m++;
    cout<<m<<endl;
}

signed main()
{	
    ios::sync_with_stdio(false), cin.tie(0),cout.tie(0); 
    int t = 1;
    //cin>>t;
    while (t--){
        sovle();
    }

    return 0;
}

Problem - 794C - Codeforces

每个人都想达到自己的目标,让字典序最大化或最小化。

首先我们要确定,A一定会放手中最小的(n+1)/2个,B一定会放手中最大的n/2个。其他都舍去

换位思考会发现,到A操作时,如果B剩余的字母全小于等于A的,那么A就要占最后放手中最大的

反之A就要占前面放最小的。到B操作时,如果A剩余的字母全大于等于B的,那么B就要占最后放手中最小的。

#include<bits/stdc++.h>
#define endl '\n'
#define mk make_pair
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 1e5+10;
const int mod = 998244353;
int n,m,k,l,cnt;

void sovle(){
    string a,b;
    cin>>a>>b;
    n=a.size();
    string c,d;
    map<char,int>ax,bx;
    sort(a.begin(),a.end());
    sort(b.begin(),b.end(),greater<char>());
    for(int i=0;i<(n+1)/2;i++){
        ax[a[i]]++;
    }
    for(int i=0;i<n/2;i++){
        bx[b[i]]++;
    }
    for(int i=0;i<n;i++){
        char minb='z',maxb='a',mina='z',maxa='a';
        for(char j='a';j<='z';j++){
            if(bx[j]){
                minb=min(minb,j);
                maxb=max(maxb,j);
            }
            if(ax[j]){
                mina=min(mina,j);
                maxa=max(maxa,j);
            }
        }
        if(i%2==0){
            if(maxb<=mina){
                d.push_back(maxa);
                ax[maxa]--;
            }else{
                c.push_back(mina);
                ax[mina]--;
            }
        }else{
            if(mina>=maxb){
                d.push_back(minb);
                bx[minb]--;
            }else{
                c.push_back(maxb);
                bx[maxb]--;
            }
        }
    }
    reverse(d.begin(),d.end());
    cout<<c<<d;
}

signed main()
{	
    ios::sync_with_stdio(false), cin.tie(0),cout.tie(0); 
    int t = 1;
    //cin>>t;
    while (t--){
        sovle();
    }

    return 0;
}

Problem - 1416B - Codeforces

对于-1的情况,就是所有的数之和对n取余不为0,因为操作之后的总和是不变的。

对于这个操作,我们发现如果对1和j(j>=2)进行操作是最有价值的(因为i=1时能对任意值进行加减),所以我们考虑能不能把所有数都加到a1上。如果想把一个数全部转移到a1上,那么这个数必须是i的倍数,如果不是呢?我们发现ai是严格大于等于1的,那么我们从左往右遍历,总和必然大于等于i,也就是说,我们可以通过先把a1借给ai,再将ai全部还给a1,这样一次操作数就是2,最后我们只需要将平均数分给每个ai(i>=2)就可以了,操作数为3*(n-1)。

#include<bits/stdc++.h>
#define endl '\n'
#define mk make_pair
#define int long long
using namespace std;
typedef pair<int, int> PII;
const int N = 2e5+10;
const int mod = 998244353;
int n,m,k,l,cnt;
int a[10005];

void sovle(){
    cin>>n;
    bool ok=0;
    int sum=0;
    for(int i=1;i<=n;i++){
        cin>>a[i];
        sum+=a[i];
        if(a[i]>=i){
            ok=1;
        }
    }
    if(sum%n){
        cout<<-1<<endl;
        return;
    }
    cout<<3*(n-1)<<endl;
    for(int i=2;i<=n;i++){
        if(a[i]%i){
            cout<<1<<' '<<i<<' '<<i-a[i]%i<<endl;
            cout<<i<<' '<<1<<' '<<(a[i]+i-1+i-a[i]%i)/i<<endl;
        }else{
            cout<<1<<' '<<i<<' '<<0<<endl;
            cout<<i<<' '<<1<<' '<<a[i]/i<<endl;
        }
    }
    sum/=n;
    for(int i=2;i<=n;i++){
        cout<<1<<' '<<i<<' '<<sum<<endl;
    }
}

signed main()
{	
    ios::sync_with_stdio(false), cin.tie(0),cout.tie(0); 
    int t = 1;
    cin>>t;
    while (t--){
        sovle();
    }

    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值