Codeforces Round #636 (Div. 3)题解

Posted johnran

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Codeforces Round #636 (Div. 3)题解相关的知识,希望对你有一定的参考价值。

A. 给你一个n,解方程,(1+2+4+...+2^(k-1))*x=n,保证k>1。

  枚举k,可以整除时输出一个数。

技术图片技术图片
#include<bits/stdc++.h>

#define all(x) x.begin(),x.end()
#define fi first
#define sd second
#define lson (nd<<1)
#define rson (nd+nd+1)
#define PB push_back
#define mid (l+r>>1)
#define MP make_pair
#define SZ(x) (int)x.size()

using namespace std;

typedef long long LL;

typedef vector<int> VI;

typedef pair<int,int> PII;

inline int read(){
    int res=0, f=1;char ch=getchar();
    while(ch<0|ch>9){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9){res=res*10+ch-0;ch=getchar();}
    return res*f;
}

const int MAXN = 200005;

const int MOD = 1000000007;

void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;}
int mulmod(int a, int b){return 1ll*a*b%MOD;}

template<typename T>
void chmin(T& a, T b){if(a>b)a=b;}

template<typename T>
void chmax(T& a, T b){if(b>a)a=b;}

void solve(){
    int n=read();
    for(int i=2;i<=30;++i){
        int v=(1<<i)-1;
        if(n%v==0){
            cout<<n/v<<endl;
            return;
        }
    }
}

int main(){
    int t=read();
    while(t--){
        solve();
    }

    return 0;
}
View Code

 

B. 给一个偶数n,构造一个数组,前面都是偶数,后面都是奇数,且互不相同。且前面n/2个数的和与后面n/2个数的和相等。

  首先n/2不是偶数直接输出“NO”,然后就随便搞搞。

技术图片技术图片
#include<bits/stdc++.h>

#define all(x) x.begin(),x.end()
#define fi first
#define sd second
#define lson (nd<<1)
#define rson (nd+nd+1)
#define PB push_back
#define mid (l+r>>1)
#define MP make_pair
#define SZ(x) (int)x.size()

using namespace std;

typedef long long LL;

typedef vector<int> VI;

typedef pair<int,int> PII;

inline int read(){
    int res=0, f=1;char ch=getchar();
    while(ch<0|ch>9){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9){res=res*10+ch-0;ch=getchar();}
    return res*f;
}

const int MAXN = 200005;

const int MOD = 1000000007;

void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;}
int mulmod(int a, int b){return 1ll*a*b%MOD;}

template<typename T>
void chmin(T& a, T b){if(a>b)a=b;}

template<typename T>
void chmax(T& a, T b){if(b>a)a=b;}


void solve(){
    int n=read();
    if((n/2)&1){
        cout<<"NO"<<endl;
    }else{
        cout<<"YES"<<endl;
        for(int i=1;i<=n/2;++i){
            cout<<2*i<<" ";
        }
        for(int i=1;i<=n/2-1;++i){
            cout<<2*i-1<<" ";
        }
        cout<<3*n/2-1<<endl;
    }
}

int main(){
    int t=read();
    while(t--){
        solve();
    }

    return 0;
}
View Code

 

C. 给一个长度为n的数组,里面没有0。求一个正负交替的子序列,其和最大。

  首先可以发现,一段连续的正数和负数只能选一个,直接贪心选最大。

技术图片技术图片
#include<bits/stdc++.h>

#define all(x) x.begin(),x.end()
#define fi first
#define sd second
#define lson (nd<<1)
#define rson (nd+nd+1)
#define PB push_back
#define mid (l+r>>1)
#define MP make_pair
#define SZ(x) (int)x.size()

using namespace std;

typedef long long LL;

typedef vector<int> VI;

typedef pair<int,int> PII;

inline LL read(){
    LL res=0, f=1;char ch=getchar();
    while(ch<0|ch>9){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9){res=res*10+ch-0;ch=getchar();}
    return res*f;
}

const int MAXN = 200005;

const int MOD = 1000000007;

void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;}
int mulmod(int a, int b){return 1ll*a*b%MOD;}

template<typename T>
void chmin(T& a, T b){if(a>b)a=b;}

template<typename T>
void chmax(T& a, T b){if(b>a)a=b;}


void solve(){
    LL n=read();
    vector<LL> a(n);
    vector<LL> b;
    for(int i=0;i<n;++i){
        a[i]=read();
        if(i!=0){
            if(b.back()*a[i]>0){
                b.back()=max(b.back(),a[i]);
            }else{
                b.PB(a[i]);
            }
        }else{
            b.PB(a[0]);
        }
    }
    cout<<accumulate(all(b),0ll)<<endl;
}

int main(){
    LL t=read();
    while(t--){
        solve();
    }

    return 0;
}
View Code

 

D. 给你n个数的数组,n为偶数。每一个数都不超过k,修改之后的值也不能超过k。现在求最小的修改次数,使得a[i]+a[n-i+1]=const。

  考虑一下右边的这个常数,我们会发现,对于每一个二元组,是可以O(1)得到某一个常数对应的修改次数的。直接差分,O(n)做完。

技术图片技术图片
#include<bits/stdc++.h>

#define all(x) x.begin(),x.end()
#define fi first
#define sd second
#define lson (nd<<1)
#define rson (nd+nd+1)
#define PB push_back
#define mid (l+r>>1)
#define MP make_pair
#define SZ(x) (int)x.size()

using namespace std;

typedef long long LL;

typedef vector<int> VI;

typedef pair<int,int> PII;

inline int read(){
    int res=0, f=1;char ch=getchar();
    while(ch<0|ch>9){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9){res=res*10+ch-0;ch=getchar();}
    return res*f;
}

const int MAXN = 200005;

const int MOD = 1000000007;

void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;}
int mulmod(int a, int b){return 1ll*a*b%MOD;}

template<typename T>
void chmin(T& a, T b){if(a>b)a=b;}

template<typename T>
void chmax(T& a, T b){if(b>a)a=b;}

void solve(){
    int n=read(),k=read();
    vector<int> a(2*k+5,0);
    vector<int> num(n+1);
    for(int i=1;i<=n;++i)num[i]=read();

    for(int i=1;i<=n/2;++i){
        int x=num[i]+num[n-i+1];

        int l1=x-max(num[i],num[n-i+1])+1;
        int r1=x;

        int l2=x+1;
        int r2=x+k-min(num[i],num[n-i+1])+1;

        int l3=2;
        int r3=max(l3,l1);

        int l4=r2;
        int r4=2*k+1;

        a[l1]+=1;
        a[r1]-=1;

        a[l2]+=1;
        a[r2]-=1;

        a[l3]+=2;
        a[r3]-=2;

        a[l4]+=2;
        a[r4]-=2;
    }

    for(int i=1;i<=2*k;++i)a[i]=(a[i-1]+a[i]);

    cout<<*min_element(a.begin()+2,a.begin()+2*k+1)<<endl;

}


int main(){
    int t=read();
    while(t--){
        solve();
    }
    return 0;
}

/*
1
2 1
1 1
*/
View Code

 

E. 给你一个n个点,m条边的图,和m个值,要求给边分配权重,使得从a->b->c,权重和最小。

  首先考虑一种简单的情况,如果只有两个点。那么毫无疑问,我们直接bfs出最短路,贪心选择最小的边即可。现在变成三个点,其实也差不多,我们要走的路径,其实都是“一”,"Y","V"字型的。即,有一些边我们是要走两次的,肯定要选权值最小的几条边,其他的就贪心的去选就行了。现在如果想去找a->b和c->b经过了哪些点是行不通的,无论是bfs还是dfs都跑不通。原因是最短路可能不止一条,这直接导致两条路径不重合,代价变大(蒟蒻哭泣)。正确的做法是,枚举一个点,得到这个点与a,b,c,三个点的距离。然后到b的距离安排上最小的一些边权(因为要算两次),然后贪心的去选取其他的边权。正确性也是显然的,首先,两条最短路上的点一定比非路径上的点优(很显然),其次是分叉点一定比其他点优。

技术图片技术图片
#include<bits/stdc++.h>

#define all(x) x.begin(),x.end()
#define fi first
#define sd second
#define lson (nd<<1)
#define rson (nd+nd+1)
#define PB push_back
#define mid (l+r>>1)
#define MP make_pair
#define SZ(x) (int)x.size()

using namespace std;

typedef long long LL;

typedef vector<int> VI;

typedef pair<int,int> PII;

inline int read(){
    int res=0, f=1;char ch=getchar();
    while(ch<0|ch>9){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9){res=res*10+ch-0;ch=getchar();}
    return res*f;
}

const int MAXN = 200005;

const int MOD = 1000000007;

void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;}
int mulmod(int a, int b){return 1ll*a*b%MOD;}

template<typename T>
void chmin(T& a, T b){if(a>b)a=b;}

template<typename T>
void chmax(T& a, T b){if(b>a)a=b;}

void solve(){
    int n=read(),m=read(),a=read(),b=read(),c=read();
    --a;--b;--c;
    vector<vector<int>> G(n,vector<int>());

    vector<int> val(m);
    for(int i=0;i<m;++i)val[i]=read();
    sort(all(val));
    vector<LL> sum(m+1,0);
    for(int i=1;i<=m;++i)sum[i]=sum[i-1]+val[i-1];

    for(int i=1;i<=m;++i){
        int u=read();int v=read();
        --u;--v;
        G[u].PB(v);G[v].PB(u);
    }

    LL ans=1e18;

    auto bfs=[&](int x){
        vector<int> d(n,-1);
        queue<int> q;
        q.push(x);
        d[x]=0;

        while(!q.empty()){
            int u=q.front();
            q.pop();
            for(auto it:G[u]){
                if(d[it]!=-1)continue;
                else{
                    d[it]=d[u]+1;
                    q.push(it);
                }
            }
        }

        return d;
    };

    auto da=bfs(a),db=bfs(b),dc=bfs(c);

    for(int i=0;i<n;++i){
        int dx=da[i],dy=db[i],dz=dc[i];
        if(dx+dy+dz>m)continue;
        else ans=min(ans,sum[dy]+sum[dx+dy+dz]);
    }

    cout<<ans<<endl;
}

int main(){
    int t=read();
    while(t--){
        solve();
    }

    return 0;
}
/*
1
4 4 1 3 4
1 2 3 4
1 2
2 3
3 4
1 4

4
*/
View Code

 

F. 现在有一个排列,长度为n。现在的情况是,给从右端点(r=2...n),左端点随便选(l<r),的n-1个区间段,但是这个区间段是排序之后的。n-1个区间段是随机给的,现在要复原这个排列。

  枚举第一个元素,考虑对所有的区间段删掉这个元素,那么一定只有一个区间段长度为1(不是则这个第一个值不合法)。原因很显然,因为其他的删不到第一个元素。现在变成了一个子问题了,只不过第一个值变成了那个长度为1的子段的值。

  这样就能得到一些解,但是很神奇的是,这这是一个必要条件,不一定是充分的。所以我们还需要要验证这n-1个子段能不能生成。

技术图片技术图片
#include<bits/stdc++.h>

#define all(x) x.begin(),x.end()
#define fi first
#define sd second
#define lson (nd<<1)
#define rson (nd+nd+1)
#define PB push_back
#define mid (l+r>>1)
#define MP make_pair
#define SZ(x) (int)x.size()

using namespace std;

typedef long long LL;

typedef vector<int> VI;

typedef pair<int,int> PII;

inline int read(){
    int res=0, f=1;char ch=getchar();
    while(ch<0|ch>9){if(ch==-)f=-1;ch=getchar();}
    while(ch>=0&&ch<=9){res=res*10+ch-0;ch=getchar();}
    return res*f;
}

const int MAXN = 200005;

const int MOD = 1000000007;

void addmod(int& a, int b){a+=b;if(a>=MOD)a-=MOD;}
int mulmod(int a, int b){return 1ll*a*b%MOD;}

template<typename T>
void chmin(T& a, T b){if(a>b)a=b;}

template<typename T>
void chmax(T& a, T b){if(b>a)a=b;}

void solve(){
    int n=read();

    vector<set<int>> a(n-1);
    for(int i=0;i<n-1;++i){
        int k=read();
        for(int j=0;j<k;++j){
            a[i].insert(read());
        }
    }

    for(int fst=1;fst<=n;++fst){
        auto b=a;

        int ok=1;

        vector<int> ans;
        ans.PB(fst);

        for(int i=0;i<n-1;++i){
            if(SZ(b[i])>0&&b[i].count(fst)){
                b[i].erase(b[i].find(fst));
            }
        }

        for(int iter=1;iter<n;++iter){
            int cnt=0;
            int nxt=-1;

            for(int i=0;i<n-1;++i){
                if(SZ(b[i])==1){
                    ++cnt;
                    nxt=*b[i].begin();
                    b[i].clear();
                }
            }

            if(cnt>1||cnt==0){
                ok=0;break;
            }

            ans.PB(nxt);

            for(int i=0;i<n-1;++i){
                if(SZ(b[i])>0&&b[i].count(nxt)){
                    b[i].erase(b[i].find(nxt));
                }
            }
        }

        if(!ok)continue;
        else{
            for(int i=0;i<n-1;++i){
                int okok=0;
                for(int j=0;j<n;++j){
                    set<int> s;s.insert(ans[j]);
                    for(int k=j+1;k<n;++k){
                        s.insert(ans[k]);
                        if(a[i]==s){
                            okok=1;
                            break;
                        }
                    }
                }

                if(!okok){
                    ok=0;
                    break;
                }
            }

            if(ok){
                for(int i=0;i<n;++i)cout<<ans[i]<<" 
"[i==n-1];
                return;
            }
        }
    }
}


int main(){
    int t=read();
    while(t--){
        solve();
    }

    return 0;
}
View Code

 

  

以上是关于Codeforces Round #636 (Div. 3)题解的主要内容,如果未能解决你的问题,请参考以下文章

Codeforces Round #636 (Div. 3)

Codeforces Round #636 (Div. 3)题解

codeforces Round #636 D. Constant Palindrome Sum

Codeforces Round #636 (Div. 3) E—Weights Distributing

Codeforces Round #636 (Div. 3)(A~E)

Codeforces Round #636 (Div. 3) E. Weights Distributing 贪心+图