2020牛客多校第八场
G Game SET
链接:https://ac.nowcoder.com/acm/contest/5673/G
题意:
就是多组输入,每次输入给定n个字符串,每个字符串有四个属性,每个属性分别有三个选项,这三个选项用三个不同的字符串,或者用*来表示没有选项来表示,问是否存在三个字符串,他们四个属性各不相同,或者都一样。有的话输出编号,没有输出-1.
题解:先分别将这四种属性的选项用map容器赋值,简化,再O(n^3)进行遍历三个三个进行比较,看他们四个属性是否都不相同,或者都一样
注意:
*与 *之间他们的也算不同,因为表示null,所以不能算属性相同。
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<set> #include<map> using namespace std; typedef long long ll; const int maxn=2e5+7; //const ll mod=998244353; map<string,int>m; char str[105]; void init() { m["one"]=1; m["two"]=2; m["three"]=3; m["diamond"]=1; m["squiggle"]=2; m["oval"]=3; m["solid"]=1; m["striped"]=2; m["open"]=3; m["red"]=1; m["green"]=2; m["purple"]=3; m["*"]=0; } struct node{int c[5];}trans[300]; bool check(int x,int y,int z) { for(int i=1;i<=4;i++) { set<int>st; int wild=0; if(trans[x].c[i]==0)wild++; else st.insert(trans[x].c[i]); if(trans[y].c[i]==0)wild++; else st.insert(trans[y].c[i]); if(trans[z].c[i]==0)wild++; else st.insert(trans[z].c[i]); if(st.size()>1&&st.size()+wild<3)return false; } return true; } int main() { int t,n; scanf("%d",&t); init(); int cas=0; while(t--) { cas++; scanf("%d",&n); int i,j,k; for( i=1;i<=n;i++) { scanf("%s",str); k=1; for(j=1;j<=4;j++) { string a; for(k;str[k]!=']';k++) { a+=str[k]; } trans[i].c[j]=m[a]; k+=2; } } int flag=0; for(i=1;i<=n;i++) { for(j=i+1;j<=n;j++) { for(k=j+1;k<=n;k++) { if(check(i,j,k)) { flag=1;break; } } if(flag)break; } if(flag)break; } if(!flag)printf("Case #%d: -1\n",cas); else printf("Case #%d: %d %d %d\n",cas,i,j,k); } return 0; }
I Interesting Computer Game
链接:https://ac.nowcoder.com/acm/contest/5673/I
题意:
给出n对数字 a,b。在每一对数中选择一个与之前的不同的数,若没有则不选,求最多能选出多少数
题解:
先离散化一下,构建一个并查集,找出每个根节点能够联通的最多的个数,稍微根据题意修改一下
注意:
若没有出现成环的情况,则需要-1,因为最开始的根节点和它的一个子节点需要二选一
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include<map> using namespace std; typedef long long ll; const int maxn=2e5+7; //const ll mod=998244353; int a[maxn],b[maxn],fa[maxn],cnt[maxn],vis[maxn],val[maxn],ans,n,k,T; int get(int x) { if(fa[x]!=x)fa[x]=get(fa[x]); return fa[x]; }//得到x的根节点 void combine(int u,int v)//先把两个点给连接起来成为一条边 { int temp1=get(u); int temp2=get(v);// if(temp1==temp2){vis[temp1]=1;}//说明这是一个环 else { if(vis[temp1]||vis[temp2]){vis[temp1]=vis[temp2]=1;}// cnt[temp1]+=cnt[temp2];//求出每个节点所包含的节点(包括自己) fa[temp2]=temp1;//合并,v是u的父节点。 }// } void init(int t) { for(int i=1;i<=t;i++) { fa[i]=i; cnt[i]=1; vis[i]=0;//表示是否有成环 } k=1;ans=0; }//初始化 int main() { scanf("%d",&T); int cas=0; while(T--) { cas++; scanf("%d",&n); init(n*2); for(int i=1;i<=n;i++) { scanf("%d%d",&a[i],&b[i]); val[k++]=a[i]; val[k++]=b[i];//把所有的数放入一个大的数组里面去 } sort(val+1,val+k); int t= unique(val+1,val+k)-val-1;//表示一共有多少个不重复的数字,此时的val已经是去重后的函数 //printf("%d",t); for(int i=1;i<=n;i++) { a[i]=lower_bound(val+1,val+t,a[i])-val;//表示原先这个数在去重,排大小数列数列中的位置 b[i]=lower_bound(val+1,val+t,b[i])-val; //printf("%d %d\n",a[i],b[i]); }//离散化,O(n)//a[i],b[i]就只能是1~t里面的数了 for(int i=1;i<=n;i++) { combine(a[i],b[i]);//连接a[i],b[i]的编号。 } for(int i=1;i<=t;i++) { if(get(i)==i)//根节点(找到根节点) { ans+=cnt[i]+vis[i]-1;//表示是否成环,若没有成环就要减去初始的一个(根节点直接加进去了) } } printf("Case #%d: %d\n",cas,ans); //for(int i=1;i<=t;i++)printf("%d ",val[i]); //for(int i=1;i<=t;i++)printf("%d ",get(i)); } return 0; }
K Kabaleo Lite
链接:https://ac.nowcoder.com/acm/contest/5673/K
题意:
就是说有n盘菜,第i个菜有a[i]个价值,和个数b[i],然后要求一堆人必须连续的吃,求吃得到的最大的价值
题解:
其实就是求前缀和问题,人数从b[1]开始慢慢减少,然后只要连续的前缀和大于0就进行叠加
注意:
它还卡了快读,最后的和大于ll范围,需要用到__int128,但是windows系统上clion好像又对这个玩意报错,玄学。
代码:
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef long long ll; const int maxn=1e5+7; const int inf=0x3f3f3f3f; //const ll mod=998244353; ll a[maxn],b[maxn],s[maxn]; inline __int128 read(){ //__int128 可以换成 int longlong 基于自己的需求即可,板子 __int128 x=0,f=1; char ch=getchar(); while(ch<'0'||ch>'9'){ if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x*f; } inline void out(__int128 x){ //输出 if(x<0){ putchar('-'); x=-x; } if(x>9) out(x/10); putchar(x%10+'0'); } int main() { int t,n,l,r;__int128 ans; t=read(); int cas=0; while(t--) { cas++; n=read();s[0]=0;b[0]=inf;a[0]=0; for(int i=1;i<=n;i++) { a[i]=read(); s[i]=s[i-1]+a[i]; } for(int i=1;i<=n;i++) { b[i]=read(); b[i]=min(b[i],b[i-1]);//找到当前最小的限制人数 } ans=a[1]*b[1]; r=l=1; while(r<=n) { while(s[r]<=s[l]&&r<=n)r++;//分块 if(r==n+1)break;//全是小于s[1] ans+=b[r]*(s[r]-s[l]); l=r; } printf("Case #%d: %lld ",cas,b[1]); out(ans); printf("\n"); } return 0; }