南昌不翻车 Codeforces Round #592 (Div. 2) C D E

https://codeforces.com/contest/1244/problem/C

C:

 题目大意:找X,Y,Z满足上式。

题目思路:

             明显Z是补n的作用,那么只要让x+y尽量的小就可以了,w>d那么就尽量让x多一点,y少一点。

             枚举y [ 0 , w )  ,如果 y 大于w了,那么意思就是包含了大于w个d,那么为什么不分给 x 让y变小点呢。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int main()
{
    ll n,p,w,d;
    cin>>n>>p>>w>>d;
    ll y;
    for(int i=0;i<w;i++){
        if( ( p-d*i )%w ==0){
            y = i;break;
        }
    }
    ll x = (p-d*y)/w;
    ll z = n-x-y;
    if(x<0||y<0||z<0){
        cout<<-1<<endl;
    }
    else cout<<x<<" "<<y<<" "<<z<<endl;
}

D:

题目大意:给一棵树,要求相邻三个点颜色不同的最小花费。

    很容易看出是一条链,那么端点颜色定了的话,全部的颜色就都确定了,只有六种情况,枚举一遍就行

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll MAXN = 1e5+5;
vector<int>v[MAXN];
ll c[5][MAXN];
ll vis[MAXN];
ll col[MAXN],cou[MAXN];
struct node
{
    ll co,id;
    node(ll a,ll b){
        co = a;id = b;
    }
};
ll ret = 0;
ll idx;
void dfs(ll fa,ll x,ll now_c,ll a,ll b,ll C)
{
    col[x] = now_c;
    ll len = v[x].size();
    for(ll i=0;i<len;i++){
        ll to = v[x][i];
        if(to == fa)continue;
        if(now_c == a)
            dfs(x,to,b,a,b,C);
        if(now_c == b)
            dfs(x,to,C,a,b,C);
        if(now_c == C)
            dfs(x,to,a,a,b,C);
    }
}
int main()
{
    ll n;
    cin>>n;
    for(ll i=1;i<=3;i++){
        for(ll j=1;j<=n;j++){
            cin>>c[i][j];
        }
    }
    for(ll i=1;i<n;i++){
        ll a,b;
        cin>>a>>b;
        v[a].push_back(b);
        v[b].push_back(a);
    }
    bool f=1;
    for(ll i=1;i<=n;i++){
        if(v[i].size()>=3)f=0;
    }
    if(!f){
        cout<<-1<<endl;
        return 0;
    }
    ll ans = 1ll<<62;
    idx = 0;
    for(ll i=1;i<=n;i++){
        ll len  =v[i].size();
        if(len == 1){
            idx = i;
            break;
        }
    }
    ll bb[5];
    bb[1] = 1; bb[2] = 2; bb[3] = 3;
    do{
        ll ret = 0;
        dfs(0,idx,bb[1],bb[1],bb[2],bb[3]);
        for(ll i=1;i<=n;i++){
            ret += c[col[i]][i];
        }
        if(ans > ret){
            ans = ret;
            for(ll i=1;i<=n;i++){
                cou[i] = col[i];
            }
        }
    }while(next_permutation(bb+1,bb+4));
    cout<<ans<<endl;
    for(ll i=1;i<=n;i++){
        cout<<cou[i]<<" ";
    }
    cout<<endl;
}

E: E. Minimizing Difference

https://codeforces.com/contest/1244/problem/E

题目大意:

        给一个数组,k次操作,每次找一个数字+1或者-1,问最小差距可以减小到多少。

题目思路:

       和2019某场网络赛的签到很相似,那个是取一个还要放回来,这个取走放回是单独的,比那个简单一点。

首先排序,然后肯定是高的往下靠拢,低的往上靠拢,那么选择下边的还是上边的呢,这取决与谁使得总差距减小的花费的大小,定义两根指针,一个idx1从前往后跳,一个idx2从后往前跳,意思就是当前前边的被填平了多少和后边被填平了多少。

直接模拟就行了,知道k<0或者,idx>=idx2

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll MAXN = 1e5+5;
ll a[MAXN];
ll n,k;
int main()
{
    cin>>n>>k;
    for(ll i=1;i<=n;i++){
        cin>>a[i];
    }
    sort(a+1,a+1+n);
    ll idx1=1,idx2=n;
    for(ll i=2;i<=n;i++){
        if(a[i] == a[1]){
            idx1 = i;
        }
        else break;
    }
    for(ll i=n-1;i>=1;i--){
        if(a[i] == a[n]){
            idx2 = i;
        }
        else break;
    }
    ll dis = a[n] - a[1];
    ll sum = 0;
    while(idx1<idx2)
    {
        if(idx1 > n-idx2+1){
            ll now_dis = a[idx2]-a[idx2-1];
            ll Max = (n-idx2+1)*now_dis;
            if(k >= Max){
                ll x = lower_bound(a+1,a+1+n,a[idx2-1])-a;
                idx2 = x;
                k -= Max;
                dis -= now_dis;
            }
            else{
                ll f = k/(n-idx2+1);
                k = 0;
                dis -= f;
            }
        }
        else{
            ll now_dis = a[idx1+1]-a[idx1];
            ll Max = (idx1)*now_dis;
            if(k >= Max){
                ll x = upper_bound(a+1,a+1+n,a[idx1+1])-a-1;
                idx1 = x;
                k -= Max;
                dis -= now_dis;
            }
            else{
                ll f = k/(idx1);
                k = 0;
                dis -=f;
            }
        }
        if(k<=0)break;
    }
    if(k){
        cout<<0<<endl;
    }
    else cout<<dis<<endl;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值