[关闭]
@Asuna 2017-02-23T05:12:46.000000Z 字数 3733 阅读 777

2016寒假集训队第三次作业(stl)

题解


Probllem A:Moo University - Financial Aid

题意:从C头牛里选N头牛,每头牛有两个属性,得分score和经费aid,在总经费不超过F的情况下使得N头牛的得分中位数最大。

题解:先将C头牛按得分score升序,然后,我们假设每个i都可以作为中位数,a[i].l记录在i之前(也就是分数比它低)的总经费,a[i].r记录在i之后(也就是分数比它高)的总经费,最后,由于是求最大的中位数,所以,得分从后往前循环,第一个满足a[i].l+a[i].y+a[i].r的i就是最优解。在求a[i].l和a[i].r的时候用优先队列把最大值弹出。

参考代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. #include<queue>
  6. using namespace std;
  7. int tot,n,c,f;
  8. struct node
  9. {
  10. int x;
  11. int y;
  12. int l;
  13. int r;
  14. }a[100005];
  15. bool cmp(node a,node b)
  16. {
  17. return a.x<b.x;
  18. }
  19. int main()
  20. {
  21. memset(a,0,sizeof(a));
  22. cin>>n>>c>>f;
  23. for(int i=1; i<=c; i++)
  24. cin>>a[i].x>>a[i].y;
  25. sort(a+1,a+1+c,cmp);
  26. if (n>1)
  27. {
  28. priority_queue<int>q;
  29. int p,t,sum=0;
  30. for (int i=1; i<=n/2; i++)
  31. {
  32. p=a[i].y;
  33. q.push(p);
  34. sum+=p;
  35. }
  36. for (int i=n/2+1; i<=c-n/2; i++)
  37. {
  38. a[i].l=sum;
  39. p=q.top();
  40. t=a[i].y;
  41. if (t<p)
  42. {
  43. q.pop();
  44. q.push(t);
  45. sum=sum-p+t;
  46. }
  47. }
  48. while (q.size()) q.pop();
  49. sum=0;
  50. for (int i=c; i>=c-n/2+1; i--)
  51. {
  52. p=a[i].y;
  53. q.push(p);
  54. sum+=p;
  55. }
  56. for (int i=c-n/2; i>=n/2+1; i--)
  57. {
  58. a[i].r=sum;
  59. p=q.top();
  60. t=a[i].y;
  61. if (t<p)
  62. {
  63. q.pop();
  64. q.push(t);
  65. sum=sum-p+t;
  66. }
  67. }
  68. }
  69. int ans=-1;
  70. for (int i=c-n/2; i>=n/2+1; i--)
  71. {
  72. tot=a[i].l+a[i].r+a[i].y;
  73. if (tot<=f)
  74. {
  75. ans=a[i].x;
  76. break;
  77. }
  78. }
  79. cout<<ans<<endl;
  80. return 0;
  81. }

Problem B:Sockets

题意:给出n个电脑,m个电源,电脑有一个值ai,电源有一个值bi,电脑和电源能够配对当且仅当ai=bi。有无穷多个适配器,每对电源用一个适配器bi就减少一半(向上取整)。一个电源可以用很多次适配器。求最多配对多少电脑和电源,以及在最多配对下用的最少的适配器。还要输出方案。

题解:贪心:将电源按照从小到大依次尝试和电脑配对,如果能够配对成功就配对。

证明:假设按照这个顺序配对会使得配对数减少,也就是说有一个比他大的电源本应该和这个电脑相配。因为这两个电源都匹配到了这个电脑,所以当前枚举的电源往下能够匹配的电脑也能被那个比他大的电源匹配掉。

参考代码:

  1. #include<iostream>
  2. #include<cstdlib>
  3. #include<cstring>
  4. #include<cstdio>
  5. #include<cmath>
  6. #include<map>
  7. #include<algorithm>
  8. using namespace std;
  9. int n,m,c,u,x;
  10. int s[200005],a[200005],b[200005];
  11. multimap<int,int> p;
  12. int main()
  13. {
  14. memset(a,-1,sizeof(a));
  15. cin>>n>>m;
  16. for (int i=1; i<=n; i++)
  17. {
  18. cin>>x;
  19. p.insert(make_pair(x,i));
  20. }
  21. for (int i=1; i<=m; i++)
  22. cin>>s[i];
  23. for (int i=0; i<=30; i++)
  24. {
  25. for (int j=1; j<=m; j++)
  26. {
  27. if (a[j]==-1)
  28. {
  29. multimap<int,int>::iterator t=p.find(s[j]);
  30. if (t!=p.end())
  31. {
  32. a[j]=i;
  33. b[t->second]=j;
  34. c++;
  35. u+=i;
  36. p.erase(t);
  37. }
  38. }
  39. }
  40. for (int j=1; j<=m; j++)
  41. {
  42. if (s[j]%2==1) s[j]=s[j]/2+1;
  43. else s[j]=s[j]/2;
  44. }
  45. }
  46. cout<<c<<" "<<u<<endl;
  47. for( int i=1; i<=m; i++)
  48. {
  49. if (a[i]==-1)
  50. cout<<0<<" ";
  51. else cout<<a[i]<<" ";
  52. }
  53. cout<<endl;
  54. for(int i=1; i<=n; i++)
  55. cout<<b[i]<<" ";
  56. cout<<endl;
  57. return 0;
  58. }

Problem C:HDU Today

题意:最短路径问题。

题解:把相对应的字符串转化一下,其中的信息存储到二维数组中,然后用迪杰斯特拉算法求解就行了。

参考代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. using namespace std;
  5. int map[155][155],f[155],k,minn,p,n,a,b,x,j,ans;
  6. bool bo[155];
  7. char s1[155],s2[155],na[155][155];
  8. int dijkstra(int v)
  9. {
  10. for (int i=0; i<k; i++)
  11. {
  12. bo[i]=0;
  13. f[i]=map[v][i];
  14. }
  15. bo[v]=1;
  16. f[v]=0;
  17. for (int i=0; i<k; i++)
  18. {
  19. minn=100000000;
  20. for (int j=0; j<k; j++)
  21. if (bo[j]==0 && minn>f[j])
  22. {
  23. minn=f[j];
  24. p=j;
  25. }
  26. if (minn==100000000) break;
  27. bo[p]=1;
  28. for (int j=0; j<k; j++)
  29. if (bo[j]==0 && f[j]>(f[p]+map[p][j]))
  30. f[j]=f[p]+map[p][j];
  31. }
  32. return f[1];
  33. }
  34. int main()
  35. {
  36. while (cin>>n)
  37. {
  38. if (n==-1) break;
  39. for (int i=0; i<155; i++)
  40. for (int j=0; j<155; j++)
  41. map[i][j]=100000000;
  42. cin>>na[0]>>na[1];
  43. k=2;
  44. for (int i=0; i<n; i++)
  45. {
  46. cin>>s1>>s2>>x;
  47. for (j=0; j<k; j++)
  48. if (strcmp(s1,na[j])==0)
  49. {
  50. a=j;
  51. break;
  52. }
  53. if (j==k)
  54. {
  55. strcpy(na[k],s1);
  56. a=k;
  57. k++;
  58. }
  59. for (j=0; j<k; j++)
  60. if (strcmp(s2,na[j])==0)
  61. {
  62. b=j;
  63. break;
  64. }
  65. if (j==k)
  66. {
  67. strcpy(na[k],s2);
  68. b=k;
  69. k++;
  70. }
  71. if (map[a][b]>x) map[a][b]=x;
  72. if (map[b][a]>x) map[b][a]=x;
  73. }
  74. if (strcmp(na[0],na[1])==0) cout<<0<<endl;
  75. else
  76. {
  77. ans=dijkstra(0);
  78. if (ans>=100000000) cout<<-1<<endl;
  79. else cout<<ans<<endl;
  80. }
  81. }
  82. return 0;
  83. }

Problem F:Pearls in a Row

题意:把一段项链,分成多小段,每一小段至少存在两个相同的类型的珍珠,求最多能分成多少段,如果不能分,则输出-1。

题解:用map记录当前一段某类型的珍珠是否出现过,如果当前珍珠的类型已出现过,则将其与前面的珍珠分成一段。

参考代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<set>
  5. using namespace std;
  6. int n,a[300005],k,x;
  7. set<int> s;
  8. int main()
  9. {
  10. cin>>n;
  11. for (int i=1; i<=n; i++)
  12. {
  13. cin>>x;
  14. if (s.count(x)==0) s.insert(x);
  15. else
  16. {
  17. a[k]=i;
  18. k++;
  19. s.clear();
  20. }
  21. }
  22. //for (int i=0; i<k; i++)
  23. // cout<<a[i]<<endl;
  24. //cout<<endl;
  25. if (k==0) cout<<-1<<endl;
  26. else
  27. if (k==1)
  28. {
  29. cout<<k<<endl;
  30. cout<<1<<" "<<n<<endl;
  31. }
  32. else
  33. {
  34. cout<<k<<endl;
  35. cout<<1<<" "<<a[0]<<endl;
  36. for (int i=0; i<k-2; i++)
  37. cout<<a[i]+1<<" "<<a[i+1]<<endl;
  38. cout<<a[k-2]+1<<" "<<n<<endl;
  39. }
  40. return 0;
  41. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注