题目链接

赛时难度:G>F>E>C>D>B>A

补题难度F>C>G>E>D>B>A

F也是一个模拟题,只是比较的难,我没写出来。。。

这场打的莫名奇妙,主要是被C卡了,C这个玄学题

题意:一支球队在一个赛季有n场足球赛,每场足球赛有三种结果。赢:得w分;平局:得d分;输:不得分。已知最后这支球队得了p分,但是不知道这支球队胜负平的情况,让你求一组可行解。

扩展欧几里得做法,我不太会:参考博客

做法1:

    #include <iostream>
    #include <queue>
    #include <cstring>
    #include <algorithm>
     
    using namespace std;
     
    typedef long long LL;
     
    void exgcd(LL a, LL b, LL& x, LL& y, LL& c) {
        if(!b) {y = 0; x = 1; c = a; return;}
        exgcd(b,a%b,y,x,c); y -= a/b*x;
    }
      
    int main() {
    	LL n,p,w,d;
    	cin >> n >> p >> w >> d;
    	// wx+dy = gcd w,d
    	LL x,y,c;
    	exgcd(w,d,x,y,c);
    	LL v1 = p/w,v2 = 0,m = p%w;
    	v2 = m/d; m = m%d;
    //cout << x << " " <<y<<"\n";
    	if (m%c == 0) {
    		LL t = m/c;
    		v1 += t*x;
    		v2 += t*y;
    		LL t1 = w/c,t2 = d/c;
    		// +t1 -t2
    		while (v1 < 0) {
    			v1 += t2;
    			v2 -= t1;
    			if (v2 < 0) {
    				puts("-1");
    				return 0;
    			}
    		}
    		while (v2 < 0) {
    			v1 -= t2;
    			v2 += t1;
    			if (v1 < 0) {
    				puts("-1");
    				return 0;
    			}
    		}
    		while (n-v1-v2 < 0) {
    			if (t1 > t2) {
    				v1 += t2;
    			    v2 -= t1;
    			    if (v2 < 0) {
    				  puts("-1");
    				  return 0;
    			    }
    			} else if (t1 < t2) {
    				v1 -= t2;
    			    v2 += t1;
    			    if (v1 < 0) {
    			 	  puts("-1");
    				  return 0;
    			    }
    			} else {
    				puts("-1");
    				return 0;
    			}
    		}
    		if (v1>=0 && v2>=0 && n-v1-v2>=0) {
    			cout << v1 << " " << v2 << " " << n-v1-v2 << "\n";
    			return 0;
    		}
    	}
    	puts("-1");
        return 0;
    }

做法2:参考博客

题解:暴力即可。枚举平局场数,可以将平局局数限制在 w - 1。因为对于同样的分数 w * d,可以赢d场,可以平w场,但是题目保证d严格小于w,所以赢d场肯定最优。
 

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main()
{
    ll n, p, d, w;
    cin>>n>>p>>w>>d;
    for(ll i = 0; i <= n && i <= 100000; ++i){
        ll tmp = p - i * d;
        if(tmp >= 0 && tmp % w == 0){
            ll t = tmp / w;
            if(t + i <= n){
                printf("%lld %lld %lld\n", t, i, n - t - i);
                return 0;
            }
        }
    } 
    puts("-1");
}

D. Paint the Tree

题意:给你一颗树,每个点可以染三个颜色中的一个,每个节点染一种颜色有对应的花费。。

现要求相邻的三个点的颜色不能相同,问如何染色使得花费最小

做法:通过简单的观察可以知道,只有一条链的时候才能成功染色,否则输出-1

那么枚举前两个节点的颜色,所有节点的染色情况就可以得到了。

挺水的一题。。。。。

#include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=1e5+10;
    int du[N];
    vector<int>G[N];
    int n;
    int a[4][N],b[N],c[N];
    ll mi,ans;
    void dfs(int u,int x,int y,int fa)
    {
        //printf("u:%d\n",u);
        for(int v:G[u])
        {
            if(v==fa) continue;
            b[v]=6-x-y;
            ans+=a[b[v]][v];
            dfs(v,b[v],x,u);
        }
    }
    int main()
    {
        scanf("%d",&n);
        for(int i=1;i<=n;++i) scanf("%d",&a[1][i]);
        for(int i=1;i<=n;++i) scanf("%d",&a[2][i]);
        for(int i=1;i<=n;++i) scanf("%d",&a[3][i]);
        bool flag=1;
        for(int i=1;i<n;++i)
        {
            int u,v;
            scanf("%d%d",&u,&v);
            G[u].push_back(v);
            G[v].push_back(u);
            du[u]++;
            du[v]++;
        }
     
        int id=-1;
        mi=0x3f3f3f3f3f3f3f3f;
        for(int i=1;i<=n;++i) {
            if(du[i]>=3) flag=0;
            if(du[i]==1) id=i;
        }
        if(!flag) {
            printf("-1\n");
            return 0;
        }
        //printf("****\n");
        for(int i=1;i<=3;++i){
            for(int j=1;j<=3;++j)
            {
                if(i==j) continue;
                b[id]=i;
                b[G[id][0]]=j;
     
                ans=a[i][id];
                ans+=a[j][G[id][0]];
                dfs(G[id][0],j,i,id);
                //printf("aid:%d ag:%d\n",a[i][id],a[j][G[id][0]]);
                if(ans<mi)
                {
                    mi=ans;
                    for(int k=1;k<=n;++k) c[k]=b[k];
                }
                mi=min(ans,mi);
            }
        }
        printf("%lld\n",mi);
        for(int i=1;i<=n;++i) printf("%d ",c[i]);
    }

E. Minimizing Difference

题意:给你一个数组a[i]和一个k,每次可以选择一个值,要么将其增一,要么减一。问最多执行k次操作,问最后的序列中最大值减最小值的答案最小是多少?

做法:将数组排序去重,然后判断左端点和右端点的数量小的一端进行操作即可。。

也挺水,可惜没机会看这题。。。

#include<bits/stdc++.h>
    using namespace std;
    const int N=1e5+10;
    typedef long long ll;
    int a[N];
    ll k;
    map<int,int>vis;
    int n;
    int main()
    {
        cin>>n>>k;
        for(int i=1;i<=n;++i) {
            scanf("%d",&a[i]);
            vis[a[i]]++;
        }
        sort(a+1,a+1+n);
        n=unique(a+1,a+1+n)-a-1;
     
     
     
        int l=1,r=n;
        int mi=a[1],mx=a[n];
        //printf("n:%d\n",n);
     
        while(l<r)
        {
            //printf("vis[l]:%d vis[r]:%d\n",vis[a[l]],vis[a[r]]);
            if(vis[a[l]]<vis[a[r]]){
                ll d=a[l+1]-a[l];
                d=d*vis[a[l]];
                if(k>=d)
                {
                    k-=d;
                    vis[a[l+1]]+=vis[a[l]];
                    mi=a[l+1];
                }
                else{
                    ll t=k/vis[a[l]];
                    mi=a[l]+t;
                    k-=t*vis[a[l]];
                    break;
                }
                ++l;
            }
            else{
                ll d=a[r]-a[r-1];
                d=d*vis[a[r]];
                //printf("d:%lld\n",d);
                if(k>=d){
                    k-=d;
                    vis[a[r-1]]+=vis[a[r]];
                    mx=a[r-1];
                }
                else{
                    ll t=k/vis[a[r]];
                    k-=t*vis[a[r]];
                    mx=a[r]-t;
                    break;
                }
                --r;
            }
            //printf("l:%d r:%d k:%lld\n",l,r,k);
        }
        //printf("l:%d r:%d mx:%d mi:%d k:%lld\n",l,r,mx,mi,k);
        //printf("vr:%d vl:%d\n",vis[a[r]],vis[a[l]]);
        printf("%d\n",mx-mi);
    }

G. Running in Pairs

题意:题意比较难懂,主要是有两个跑道,每个跑道有n个人,每个人的奔跑时间是1~n的排列,

第一对人开始跑,每个跑道只能一个人,那么这次的时间消费等于最慢的人时间。。

现给你一个k,问你如何分配两个跑道的人,使得时间消耗最大且不超过k。。

做法:Codeforces Round #592 (Div. 2)(C(扩展欧几里得),D(模拟),E(模拟),G(思维 模拟))_ios

参考来自:javascript:void(0)

    #include<bits/stdc++.h>
    using namespace std;
    const int N=1e6+10;
    typedef long long ll;
    int n;
    ll k;
    int a[N],b[N];
    int main()
    {
        cin>>n>>k;
        if(k<1ll*n*(n+1)/2){
            printf("-1");
            return 0;
        }
        for(int i=1;i<=n;++i)a[i]=b[i]=i;
        int l=1;
        ll sum=1ll*n*(n+1)/2;
        //printf("sum:%lld\n",sum);
        for(int i=n;i>=1&&i>l;--i)
        {
            ll t=i-l;
            //printf("i:%d t:%lld\n",i,t);
            if(sum+t<=k&&sum+t>sum) {
                swap(a[i],a[l]);
                ++l,sum=sum+t;
            }
        }
        printf("%lld\n",sum);
     
        for(int i=1;i<=n;++i) printf("%d ",a[i]);
        puts("");
        for(int i=1;i<=n;++i) printf("%d ",b[i]);
    }