[关闭]
@suixinhita 2017-10-24T00:52:39.000000Z 字数 3642 阅读 897

10.19周四例行测试

...反正就是挂挂挂..也没什么可以说的..

直接题解

T1 升职数

此处输入图片的描述


emm...基本还是很好想到是要直接dfs换成序列来做的,但是之后求区间有多少大于的就蒙蔽了...
问题可以等价于区间第k大(但是可以很简单)
本来试图苟个主席树,后来没苟住,放弃了。
其实可以换个方向考虑。
考试的时候一直试图排序区间,无果,之后发现是排序权值更好一点。


正确的解法就是dfs转化成区间。
之后对于每一个节点都进行权值的排序,在序列相应位置按照权值大小加入,查询即可。

  1. #include<cstdio>
  2. #include<algorithm>
  3. using namespace std;
  4. const int N=1e6+5;
  5. struct data{
  6. int id,l,r,p;
  7. }a[N];
  8. struct edge{
  9. int to,next;
  10. }e[N];
  11. int head[N],gs;
  12. void adde(int fr,int to)
  13. {
  14. e[++gs].to=to,e[gs].next=head[fr],head[fr]=gs;
  15. }
  16. int tr[N],n,cnt;
  17. int lowbit(int x) {return x&(-x);}
  18. int getsum(int p)
  19. {
  20. int an=0;
  21. while(p)
  22. {
  23. an+=tr[p];
  24. p-=lowbit(p);
  25. }
  26. return an;
  27. }
  28. void add(int p,int x)
  29. {
  30. while(p<=n)
  31. {
  32. tr[p]+=x;
  33. p+=lowbit(p);
  34. }
  35. }
  36. int ans[N];
  37. void dfs(int u)
  38. {
  39. a[u].l=++cnt;
  40. for(int i=head[u];i;i=e[i].next)
  41. {
  42. int v=e[i].to;
  43. dfs(v);
  44. }
  45. a[u].r=cnt;
  46. }
  47. bool cmp(data x,data y) {return x.p>y.p;}
  48. void solve()
  49. {
  50. dfs(1);
  51. sort(a+1,a+1+n,cmp);
  52. for(int i=1;i<=n;++i)
  53. {
  54. ans[a[i].id]=getsum(a[i].r)-getsum(a[i].l-1);
  55. add(a[i].l,1);
  56. }
  57. for(int i=1;i<=n;++i) printf("%d\n",ans[i]);
  58. }
  59. inline int read()
  60. {
  61. int x=0;char c=getchar();
  62. while(c<'0'||c>'9') c=getchar();
  63. while(c>='0'&&c<='9') x=x*10+c-'0',c=getchar();
  64. return x;
  65. }
  66. int main()
  67. {
  68. int y;
  69. n=read();
  70. for(int i=1;i<=n;++i) a[i].p=read(),a[i].id=i;
  71. for(int i=2;i<=n;++i) y=read(),adde(y,i);
  72. solve();
  73. return 0;
  74. }

T2 盖楼房

此处输入图片的描述


其实这个题我属于一种:???的状态,因为我并不知道考场上这些大佬怎么a掉的...


正确解法可以算作一个分数规划(?)

首先我们可以知道,一个解是最优的当且仅当这个解分配的每一个 即使加上了 个也没什么用处,加到其他任意一层都差不多。
化成式子就是:


我们的目的就是尽量让这些值一样。
我们可以二分这个值(设为 )啊。
当然我们对于二分的条件就是,
解方程得到

二分过后可以发现,这样搞可能不能让总共的 个人全部用上,那肯定不是最优的了,所以我们思考把剩下 个人的贡献直接加上就好了(因为加到哪层楼都没有区别)

  1. #include<cmath>
  2. #include<cstdio>
  3. #include<iostream>
  4. #include<algorithm>
  5. #define ll long long
  6. #define db double
  7. using namespace std;
  8. const db eps=1e-10;
  9. const int N=1e6+5;
  10. int n;
  11. ll K;
  12. db a[N];
  13. bool check(db x)
  14. {
  15. ll ret=0;
  16. for(int i=1;i<=n;++i)
  17. {
  18. ll tmp=ceil(((-1.0+sqrt(1.0+4.0*(a[i]/x)))/2.0));
  19. ret+=tmp;
  20. if(ret>=K) return 0;
  21. }
  22. return 1;
  23. }
  24. void solve()
  25. {
  26. db l=0,r=1e10;
  27. while(fabs(l-r)>eps)
  28. {
  29. db mid=(l+r)/2.0;
  30. if(check(mid)) r=mid;
  31. else l=mid;
  32. }
  33. ll sum=0;
  34. db val=0;
  35. for(int i=1;i<=n;++i)
  36. {
  37. ll c=ceil(((-1.0+sqrt(1.0+4.0*(a[i]/l)))/2.0));
  38. sum+=c;
  39. val+=a[i]/c;
  40. }
  41. val-=((db)K-(db)sum)*l;
  42. cout<<(ll)(val+0.5)<<endl;
  43. // printf("%lld",(ll)val+0.4);
  44. }
  45. int main()
  46. {
  47. freopen("1.txt","r",stdin);
  48. scanf("%d%lld",&n,&K);
  49. for(int i=1;i<=n;++i) scanf("%lf",&a[i]);
  50. solve();
  51. return 0;
  52. }

T3 毕业照

此处输入图片的描述


说实在的我也还没苟住为什么这个是个区间dp...神佬们可能什么都能苟吧...


所以说这道题就是区间dp,状态更多一些。
设置状态


其中 分别代表了这个区间的最左和最右边的值的大小(保证其中是合法序列), 为区间左右端点。
那么我们可以设置转移如下:

于是记忆化搜索之,可以了。
注意:记忆化的时候,如果 或者 要返回

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. using namespace std;
  5. const int inf=0x3f3f3f3f;
  6. int dp[51][51][51][51];
  7. int n,a[51];
  8. int solve(int l,int r,int i,int j)
  9. {
  10. if(l>r) return 0;
  11. if(i>j) return 0;
  12. if(dp[l][r][i][j]!=-1) return dp[l][r][i][j];
  13. dp[l][r][i][j]=-inf;
  14. if(l+1<=50&&r-1>=1) dp[l][r][i][j]=max(solve(l,r-1,i,j),solve(l+1,r,i,j));
  15. if(i+1<=n) dp[l][r][i][j]=max(dp[l][r][i][j],solve(l,r,i+1,j)+(a[i]==l));
  16. if(j-1>=1) dp[l][r][i][j]=max(dp[l][r][i][j],solve(l,r,i,j-1)+(a[j]==r));
  17. if(i+1<=n&&j-1>=1) dp[l][r][i][j]=max(dp[l][r][i][j],solve(l,r,i+1,j-1)+(a[i]==r)+(a[j]==l));
  18. // if(dp[l][r][i][j]>0) printf("%d %d %d %d %d\n",l,r,i,j,dp[l][r][i][j]);
  19. return dp[l][r][i][j];
  20. }
  21. int main()
  22. {
  23. freopen("1.txt","r",stdin);
  24. freopen("11.txt","w",stdout);
  25. scanf("%d",&n);
  26. for(int i=1;i<=n;++i) scanf("%d",&a[i]);
  27. memset(dp,-1,sizeof(dp));
  28. for(int i=1;i<=n;++i)
  29. for(int k=1;k<=a[i];++k)
  30. for(int f=a[i];f<=50;++f)
  31. dp[k][f][i][i]=1;
  32. int ans=solve(1,50,1,n);
  33. /* for(int i=1;i<=n;++i)
  34. for(int j=i;j<=n;++j)
  35. for(int l=1;l<=50;++l)
  36. for(int r=1;r<=50;++r)
  37. {
  38. if(dp[l][r][i][j]<0) continue;
  39. printf("%d %d %d %d %d\n",l,r,i,j,dp[l][r][i][j]);//<<endl;
  40. }
  41. */ printf("%d",ans);
  42. return 0;
  43. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注