[关闭]
@dxbdly 2020-12-20T07:02:25.000000Z 字数 2859 阅读 156

C2020寒假训练赛2

信息学——模拟赛


C2020寒假练习赛2 & G2020寒假练习赛1

T1. BERRY PICKING

由于自己要拿的最多,则得拿的最少。

考虑拿的篮子中最少的一个为

则最优情况为她所拿的所有篮子均为

由此,考虑枚举共有个篮子为

则有两种特殊情况。

:

不满足条件,

:

此时答案为

:

除这两种情况外,考虑每颗果树上剩余的果子

发现为

所以我们可以对数组按为关键字排序。

则答案为:

  1. //The code is from dxbdly
  2. #include<bits/stdc++.h>
  3. using namespace std;
  4. inline int read()
  5. {
  6. int x=0;
  7. char c=getchar();
  8. bool f=0;
  9. while (!isdigit(c))
  10. f=f|(c=='-'),c=getchar();
  11. while (isdigit(c))
  12. x=(x<<3)+(x<<1)+(c^48),c=getchar();
  13. return f?-x:x;
  14. }
  15. int n,k;
  16. struct node{
  17. int x,mod;
  18. }a[1005];
  19. int maxx,ans;
  20. inline bool operator <(node x,node y)
  21. {
  22. return x.mod>y.mod;
  23. }
  24. int main(){
  25. n=read(),k=read();
  26. for (register int i=1;i<=n;++i)
  27. a[i].x=read(),maxx=max(maxx,a[i].x);
  28. for (register int i=1;i<=maxx;++i)
  29. {
  30. int l=0;
  31. for (register int j=1;j<=n;++j)
  32. l+=a[j].x/i,a[j].mod=a[j].x%i;
  33. if (l<(k>>1))
  34. break;
  35. if (l>=k)
  36. {
  37. ans=max(ans,i*(k>>1));
  38. continue;
  39. }
  40. sort(a+1,a+n+1);
  41. int cnt=i*(l-(k>>1));
  42. for (register int j=1;j<=k-l&&j<=n;++j)
  43. cnt+=a[j].mod;
  44. ans=max(ans,cnt);
  45. }
  46. printf("%d",ans);
  47. return 0;
  48. }

T2. LOAN REPAYMENT

首先不难想到二分答案,那么本题的困难便是部分。

直接模拟时间复杂度肯定是的,无法通过。

观察发现此形式为,所以考虑类似整除分块的做法。

则可以用根号复杂度解决

至于整除分块是啥请看G2020寒假集训Day4的整除分块部分。

  1. //The code is from dxbdly
  2. #include<bits/stdc++.h>
  3. #define int long long
  4. using namespace std;
  5. inline int read()
  6. {
  7. int x=0;
  8. char c=getchar();
  9. bool f=0;
  10. while (!isdigit(c))
  11. f=f|(c=='-'),c=getchar();
  12. while (isdigit(c))
  13. x=(x<<3)+(x<<1)+(c^48),c=getchar();
  14. return f?-x:x;
  15. }
  16. int n,k,m;
  17. inline bool check(int x)
  18. {
  19. int tot=0,day=k;
  20. while (tot<n&&day>0)
  21. {
  22. int cnt=(n-tot)/x;
  23. if (cnt<m)
  24. return (n-tot+m-1)/m<=day;
  25. int num=min(day,(n-cnt*x-tot)/cnt+1);
  26. tot+=cnt*num,day-=num;
  27. }
  28. return tot>=n;
  29. }
  30. inline void erfen()
  31. {
  32. int l=1,r=1e12;
  33. while (l<r)
  34. {
  35. int mid=(l+r+1)>>1;
  36. if (check(mid))
  37. l=mid;
  38. else
  39. r=mid-1;
  40. }
  41. printf("%lld",l);
  42. }
  43. signed main(){
  44. n=read(),k=read(),m=read();
  45. erfen();
  46. return 0;
  47. }

T3. WORMHOLE SORT

将位置抽象成点,虫洞抽象成边,则可构建一张图。

则题目要求选一些边使所有联通。

且所选边边权的最小值最大。

由于需要最小值最大,我们先将所有边按边权从大到小排序。

然后不断选边使得所有联通。

至于怎么维护联通,自然是用并查集了。

  1. //The code is from dxbdly
  2. #include<bits/stdc++.h>
  3. using namespace std;
  4. inline int read()
  5. {
  6. int x=0;
  7. char c=getchar();
  8. bool f=0;
  9. while (!isdigit(c))
  10. f=f|(c=='-'),c=getchar();
  11. while (isdigit(c))
  12. x=(x<<3)+(x<<1)+(c^48),c=getchar();
  13. return f?-x:x;
  14. }
  15. int n,m;
  16. struct node{
  17. int x,y,w;
  18. }a[100005];
  19. int father[100005],p[100005],now,ans;
  20. inline int Find(int x)
  21. {
  22. if (father[x]!=x)
  23. return father[x]=Find(father[x]);
  24. return father[x];
  25. }
  26. inline void unnion(int f1,int f2)
  27. {
  28. father[f2]=f1;
  29. }
  30. inline bool operator <(node x,node y)
  31. {
  32. return x.w>y.w;
  33. }
  34. inline bool check()
  35. {
  36. while (Find(now)==Find(p[now]))
  37. {
  38. now++;
  39. if (now>n)
  40. {
  41. printf("%d",ans);
  42. return 0;
  43. }
  44. }
  45. return 1;
  46. }
  47. int main(){
  48. n=read(),m=read();
  49. for (register int i=1;i<=n;++i)
  50. p[i]=read(),father[i]=i;
  51. for (register int i=1;i<=m;++i)
  52. a[i].x=read(),a[i].y=read(),a[i].w=read();
  53. sort(a+1,a+m+1);
  54. now=1,ans=-1;
  55. for (register int i=1;i<=m;++i)
  56. {
  57. if (!check())
  58. return 0;
  59. int f1=Find(a[i].x),f2=Find(a[i].y);
  60. if (f1!=f2)
  61. unnion(f1,f2),ans=a[i].w;
  62. }
  63. printf("%d",ans);
  64. return 0;
  65. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注