• 2020牛客暑期多校训练营(第八场)解题报告


    I

    转化为图论模型来解决问题。把给定二元组当作一条边,那么显然,如果对于一个连通块如果其是一棵树,那么就会给答案增加这个连通块大小-1的贡献、如果是一个仙人掌,那么就会给答案增加连通块大小的贡献。拿并查集即可维护我们所需的信息。由于给定二元组的值域比较大,所以需要离散化处理。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define ll long long
    ll input(){
    	ll x=0,f=0;char ch=getchar();
    	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    	return f? -x:x;
    }
    
    #define PII pair <int,int>
    #define fr first
    #define sc second
    #define mp make_pair
    
    const int N=4e5+7;
    
    vector<ll> v;
    int getid(ll x) {return lower_bound(v.begin(),v.end(),x)-v.begin()+1;}
    
    PII a[N];
    
    int fa[N],rk[N];
    int vis[N],loop[N];
    
    int find(int x){ return fa[x]==x? x:(fa[x]=find(fa[x]));} 
    void merge(int x,int y){
    	x=find(x);y=find(y);
    	if(x!=y){
    		if(rk[x]>=rk[y]){
    			loop[x]=max(loop[y],loop[x]);
    			fa[y]=x;
    			rk[x]+=rk[y];
    		}else{
    			loop[y]=max(loop[y],loop[x]);
    			fa[x]=y;
    			rk[y]+=rk[x];
    		}
    	}
    }
    
    int main(){
    	int T=input(),cas=0;
    	while(T--){
    		int n=input();
    		for(int i=1;i<=4*n;i++){
    			fa[i]=i,rk[i]=1;vis[i]=0,loop[i]=0;
    		}
    		v.clear();
    
    		for(int i=1;i<=n;i++){
    			a[i].fr=input(),a[i].sc=input();
    			v.push_back(a[i].fr),v.push_back(a[i].sc);
    		}
    
    		sort(v.begin(),v.end()),v.erase(unique(v.begin(),v.end()),v.end());
    
    		for(int i=1;i<=n;i++){
    			int u=getid(a[i].fr),v=getid(a[i].sc);
    			if(find(u)==find(v)) loop[find(u)]=1;
    			merge(u,v);
    		}
    
    		int Ans=0;
    
    		for(int i=1;i<=v.size();i++){
    			if(!vis[find(i)]){
    				Ans+=rk[find(i)]-(loop[find(i)]==0);
    				vis[find(i)]=1;
    			}
    		}
    
    		printf("Case #%d: %d
    ",++cas,Ans);
    	}
    }
    

    K

    求最多人数下的最大盈利。那么显然(b[1])就是最大人数。要求最大收益,我们只需要计算(a[i])的前缀和,从最大的前缀和往前从大到小取就是答案。显然我们可以用前缀的相关科技维护前缀最值和索引。本题数据范围超过了ll,需要使用__int128或者其它语言解决。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define ll long long
    ll input(){
    	ll x=0,f=0;char ch=getchar();
    	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    	return f? -x:x;
    }
    
    #define LL __int128
    
    const int N=1e5+7;
    
    int t[N<<4];
    
    int n;
    LL a[N],b[N],sum[N];
    LL amx[N],bmi[N];
    
    inline void write(__int128 x){
        if(x<0){
            putchar('-');
            x=-x;
        }
        if(x>9)
            write(x/10);
        putchar(x%10+'0');
    }
    
    int main(){
    	int T=input(),cas=0;
    	while(T--){
    		n=input();
    		for(int i=1;i<=n;i++) a[i]=input();
    		for(int i=1;i<=n;i++) b[i]=input();
    
    		sum[1]=a[1];
    		for(int i=2;i<=n;i++) sum[i]=sum[i-1]+a[i];
    
    		amx[1]=1,bmi[1]=b[1];
    		for(int i=2;i<=n;i++){
    			amx[i]=amx[i-1];
    			if(sum[i]>sum[amx[i]]) amx[i]=i;
    			bmi[i]=bmi[i-1];
    			if(b[i]<bmi[i]) bmi[i]=b[i];
    		}
    
    		int now=amx[n];
    		LL Ans=0,cnt=0;
    
    		while(now!=1){
    			Ans=Ans+sum[now]*(bmi[now]-cnt);
    			cnt+=(bmi[now]-cnt);
    			now=amx[now-1];
    		}
    
    		Ans=Ans+sum[1]*(bmi[1]-cnt);
    		cnt+=(bmi[1]-cnt);
    
    		printf("Case #%d: ",++cas);
    		write(cnt);printf(" ");
    		write(Ans),printf("
    ");
    	}
    }
    

    G

    大模拟题。本题可以根据性质有更好的做法。这里讲一下我比赛的时候的做法。首先我们发现一共有4种状态,每个状态只有3种类别,我们很容易的想到hash。由于数据范围很小,我们这里可以直接hash。另外我们发现,当我们知道两个状态时,第三状态我们可以直接计算出来,所以我们可以(n^2)的枚举卡片,用hash找第三张卡片。但是这里有个问题,当我们枚举某一张卡片有通配符时,我们还需要额外枚举通配符是什么,这里我们不妨猜测这些状态很小,那么我们只需要随机通配符是什么就行了,我大概随机50次就过了。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    #define ll long long
    ll input(){
    	ll x=0,f=0;char ch=getchar();
    	while(ch<'0'||ch>'9') f|=ch=='-',ch=getchar();
    	while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
    	return f? -x:x;
    }
    
    string s1[4]={"[*]","[one]","[two]","[three]"};
    string s2[4]={"[*]","[diamond]","[squiggle]","[oval]"};
    string s3[4]={"[*]","[solid]","[striped]","[open]"};
    string s4[4]={"[*]","[red]","[green]","[purple]"};
    string s="";
    
    const int N=300;
    
    struct card{
    	int a,b,c,d;
    }a[N];
    
    int mp[10007];
    
    void dfs(int dep,int x,int pos){
    	if(dep==5){mp[x]=pos;return;}
    	if(dep==1){
    		if(a[pos].a==0){
    			for(int i=1;i<=3;i++) dfs(dep+1,x*10+i,pos);
    		}else dfs(dep+1,x*10+a[pos].a,pos);
    	}
    	if(dep==2){
    		if(a[pos].b==0){
    			for(int i=1;i<=3;i++) dfs(dep+1,x*10+i,pos);
    		}else dfs(dep+1,x*10+a[pos].b,pos);
    	}
    	if(dep==3){
    		if(a[pos].c==0){
    			for(int i=1;i<=3;i++) dfs(dep+1,x*10+i,pos);
    		}else dfs(dep+1,x*10+a[pos].c,pos);
    	}
    	if(dep==4){
    		if(a[pos].d==0){
    			for(int i=1;i<=3;i++) dfs(dep+1,x*10+i,pos);
    		}else dfs(dep+1,x*10+a[pos].d,pos);
    	}		
    }
    
    void init(int n){
    	for(int i=1;i<=n;i++){
    		cin>>s;
    		string res="";
    		int dep=1;
    		for(int j=0;j<s.length();j++){
    			res+=s[j];
    			if(res[0]=='['&&res[res.length()-1]==']'){
    				if(dep==1){
    					for(int k=0;k<=3;k++)
    						if(res==s1[k]) a[i].a=k;
    					dep=2;res="";
    					continue;
    				}
    				if(dep==2){
    					for(int k=0;k<=3;k++)
    						if(res==s2[k]) a[i].b=k;
    					dep=3;res="";
    					continue;
    				}
    				if(dep==3){
    					for(int k=0;k<=3;k++)
    						if(res==s3[k]) a[i].c=k;
    					dep=4;res="";
    					continue;
    				}
    				if(dep==4){
    					for(int k=0;k<=3;k++)
    						if(res==s4[k]) a[i].d=k;
    					dep=1;res="";
    					continue;
    				}
    			}
    		}
    		
    		dfs(1,0,i);
    	}
    }
    
    int main(){
    	int T=input(),cas=0;
    	while(T--){
    		int n=input();
    
    		memset(mp,0,sizeof(mp));
    
    		init(n);
    
    		int flag=0;
    		for(int i=1;i<=n;i++){
    			for(int j=i+1;j<=n;j++){
    				for(int x=0;x<=50;x++){
    					int a0=a[i].a,a1=a[j].a,a2;
    					if(a0==0) a0=rand()%3+1;
    					if(a1==0) a1=rand()%3+1;
    					if(a0==a1) a2=a0;
    					else{
    						for(int i=1;i<=3;i++){
    							if(i!=a0&&i!=a1){
    								a2=i;break;
    							}
    						}
    					}
    
    					int b0=a[i].b,b1=a[j].b,b2;
    					if(b0==0) b0=rand()%3+1;
    					if(b1==0) b1=rand()%3+1;
    					if(b0==b1) b2=b0;
    					else{
    						for(int i=1;i<=3;i++){
    							if(i!=b0&&i!=b1){
    								b2=i;break;
    							}
    						}
    					}
    
    					int c0=a[i].c,c1=a[j].c,c2;
    					if(c0==0) c0=rand()%3+1;
    					if(c1==0) c1=rand()%3+1;
    					if(c0==c1) c2=c0;
    					else{
    						for(int i=1;i<=3;i++){
    							if(i!=c0&&i!=c1){
    								c2=i;break;
    							}
    						}
    					}
    
    					int d0=a[i].d,d1=a[j].d,d2;
    					if(d0==0) d0=rand()%3+1;
    					if(d1==0) d1=rand()%3+1;
    					if(d0==d1) d2=d0;
    					else{
    						for(int i=1;i<=3;i++){
    							if(i!=d0&&i!=d1){
    								d2=i;break;
    							}
    						}
    					}
    
    					if(mp[a2*1000+b2*100+c2*10+d2]!=0){
    						if(i==j||mp[a2*1000+b2*100+c2*10+d2]==i||mp[a2*1000+b2*100+c2*10+d2]==j) continue;
    						printf("Case #%d: %d %d %d
    ",++cas,i,j,mp[a2*1000+b2*100+c2*10+d2]);
    						flag=1;
    						break;
    					}
    					if(flag==1) break;	
    				}
    				if(flag==1) break;
    			}
    			if(flag==1) break;
    		}
    		if(!flag) printf("Case #%d: -1
    ",++cas);
    	}
    }
    
  • 相关阅读:
    微服务网关 Spring Cloud Gateway
    MySQL去重保留最大的那条记录(取最新的记录)
    第一眼就心动的人还怎么做朋友
    读《平凡的世界》
    决定放弃一个人之前,你一定在寒风里站了许久许久……
    用Nifi合并二个API、计算并生成新的API
    用nifi把hdfs数据导到hive
    用nifi把hdfs数据导到hive
    把HDFS里的json数据转换成csv格式
    导入HDFS的数据到Hive
  • 原文地址:https://www.cnblogs.com/-aether/p/13430500.html
Copyright © 2020-2023  润新知