I – Interesting Computer Game
链接:https://ac.nowcoder.com/acm/contest/5673/I
思路:这题起初我想先读入数据,记录数字个数,然后从后往前判断。这个思路应该是没有问题的,但是最后T了。虽然脑子有闪过并查集的念头,但实在不太熟悉这类题型,更不知道怎么用并查集操作。正解应该是先读入不同的数字的个数,用并查集维护不同数字之间的关系,同时再用一个same[]作为标记,可判断数字是否可以取到。例如起初的(1,2),此后fa[1]=f[2]=2,same[2]=0,只能取一个,但是再读入第二组(1,2)时,same[2]=1,可以取的数字数加一。
#include<map> #include<cstdio> using namespace std; int t,n,fa[200005],cnt,ans,a[100005],b[100005]; bool same[200005]; map<int,int> mp; int find(int x){ if(fa[x]!=x) fa[x]=find(fa[x]); return fa[x]; } int main(){ scanf("%d",&t); for(int cas=1;cas<=t;cas++){ cnt=0; int minus=0; mp.clear(); scanf("%d",&n); for(int i=0;i<n;i++){ scanf("%d%d",&a[i],&b[i]); if(mp[a[i]]==0) mp[a[i]]=++cnt; if(mp[b[i]]==0) mp[b[i]]=++cnt; } for(int i=1;i<=cnt;i++) fa[i]=i,same[i]=0; for(int i=0;i<n;i++){ int fx=find(mp[a[i]]),fy=find(mp[b[i]]); if(fx!=fy){ fa[fx]=fy; if(same[fx]||same[fy]) same[fy]=1,same[fx]=0; } else same[fy]=1; } for(int i=1;i<=cnt;i++) if(fa[i]==i&&!same[i]) minus++; printf("Case #%d: %d\n",cas,cnt-minus); } return 0; }
K – Kabaleo Lite
链接:https://ac.nowcoder.com/acm/contest/5673/K
有n道菜,第i道菜有bi盘,每盘利润为ai(利润可能为负)。遵循以下规则为每个顾客上菜:
● 每位顾客至少有一道菜。
● 每位顾客都得到从1开始的连续编号的菜,每道菜只吃一盘。
问能容纳的最大的顾客数,已经可赚取的最大利润。
思路:易得,第一盘菜的数量即为最大顾客数量。关键在于前缀和的计算和一个数组b[]保存每种菜前面最少的菜的数量。
#include<cstdio> #include<iostream> using namespace std; #define N 233333 #define ll long long int ttt,n,a[N],b[N]; long double pre[N]; int main(){ scanf("%d",&ttt); for(int tt=1;tt<=ttt;tt++){ scanf("%d",&n); for(int i=1;i<=n;i++){ scanf("%d",&a[i]); pre[i]=pre[i-1]+a[i]; } ll pd=pre[1]; a[1]=1; for(int i=2;i<=n;i++){ if(pre[i]<=pd) a[i]=0; else{ a[i]=1; pd=pre[i]; } } b[0]=100000; for(int i=1;i<=n;i++){ scanf("%d",&b[i]); b[i]=min(b[i-1],b[i]); } int st=0; long double ans=0; for(int i=n;i>=1;i--) if(a[i]){ ans+=pre[i]*(b[i]-st); st=b[i]; } printf("Case #%d: %d %.0Lf\n",tt,b[1],ans); } }