[关闭]
@Asuna 2017-04-14T17:53:20.000000Z 字数 4460 阅读 758

CQUPT 训练题题解 2017/4/3

题解


Problem A:Country Roads

题意:求某个点到各点的代价,两点间某条路径的代价定义为路径上权值最大的边的权值,而两点间的权值表示为它们之间所有路径代价的最小值。

题解:dist[u]表示从原点到点u的路径的代价,用Dijkstra。最后注意判断重边。

参考代码:

  1. #include<iostream>
  2. #include<cstring>
  3. #include<cstdio>
  4. #include<cmath>
  5. #include<cstdlib>
  6. #include<vector>
  7. #include<queue>
  8. using namespace std;
  9. typedef pair <int, int> p;
  10. int dist[510];
  11. priority_queue < p, vector<p>, greater<p> > qu;
  12. struct node
  13. {
  14. int nxt;
  15. int w;
  16. int to;
  17. }edge[40000];
  18. bool vis[510];
  19. int head[510],tot;
  20. void addedge(int from, int to, int w)
  21. {
  22. edge[tot].to=to;
  23. edge[tot].w=w;
  24. edge[tot].nxt=head[from];
  25. head[from]=tot++;
  26. }
  27. void Dijkstra(int u, int n)
  28. {
  29. while (!qu.empty())
  30. {
  31. qu.pop();
  32. }
  33. for (int i=0; i<n; i++)
  34. {
  35. dist[i]=100000000;
  36. }
  37. dist[u]=0;
  38. qu.push(make_pair(dist[u], u));
  39. while (!qu.empty())
  40. {
  41. p tmp=qu.top();
  42. qu.pop();
  43. int s=tmp.second;
  44. int d=tmp.first;
  45. for (int i=head[s]; ~i; i=edge[i].nxt)
  46. {
  47. int t=edge[i].to;
  48. int w=edge[i].w;
  49. if (dist[t]>max(d, w))
  50. {
  51. dist[t]=max(d, w);
  52. qu.push(make_pair(dist[t], t));
  53. }
  54. }
  55. }
  56. }
  57. int main() {
  58. int t, icase=1;
  59. scanf("%d", &t);
  60. while (t--)
  61. {
  62. int n, m;
  63. scanf("%d%d", &n, &m);
  64. for (int i=0; i<n; i++)
  65. {
  66. head[i]=-1;
  67. }
  68. tot=0;
  69. int u, v, w;
  70. for (int i=1; i<=m; i++)
  71. {
  72. scanf("%d%d%d", &u, &v, &w);
  73. addedge(u, v, w);
  74. addedge(v, u, w);
  75. }
  76. scanf("%d", &u);
  77. Dijkstra(u, n);
  78. printf("Case %d:\n", icase++);
  79. for (int i=0; i<n; i++)
  80. {
  81. if (dist[i]==100000000)
  82. {
  83. printf("Impossible\n");
  84. }
  85. else
  86. {
  87. printf("%d\n", dist[i]);
  88. }
  89. }
  90. }
  91. return 0;
  92. }

Problem B:How Many Zeroes?

题意:给定两个数a,b,求a到b所有数的0的个数。

题解:dp[位数][0~9][0的个数]; 然后记忆化搜索的时候 dfs(第几位,前面有没有非0的数,取数的限制,0的个数);

参考代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstring>
  4. #include<algorithm>
  5. using namespace std;
  6. long long n, m;
  7. long long cal(long long x)
  8. {
  9. if (x<0) return 0;
  10. long long ans=1, cnt=1, tmp=0;
  11. while (x>=10)
  12. {
  13. long long cur=x%10;
  14. x/=10;
  15. if (cur!=0) ans+=x*cnt;
  16. else ans+=(x-1)*cnt+tmp+1;
  17. tmp+=cur*cnt;
  18. cnt*=10;
  19. }
  20. return ans;
  21. }
  22. int main()
  23. {
  24. int t,icase=1;
  25. cin>>t;
  26. while(t--)
  27. {
  28. scanf("%d%d",&n,&m);
  29. printf("Case %d: %lld\n", icase++,cal(m)-cal(n-1));
  30. }
  31. return 0;
  32. }

Problem D:Summing up Powers

题意:求(1^K + 2^K + 3^K + ... + N^K)%2^32

题解:矩阵快速幂,由于不知道怎么搞数学公式在这个上面。。。找了篇网上写的比较详细的题解。。http://blog.csdn.net/kg20006/article/details/51057305需要注意的就是转移矩阵还有mod 2^32可以用自然溢出完成。
ps:似乎是伯努利数?有兴趣可以baidu一下伯努利数的相关题目,似乎还蛮多的好像也有点用但是我看不怎么懂。。。。

参考代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. using namespace std;
  6. const long long mod=((long long)1<<32);
  7. long long k,siz,n,C[60][60];
  8. struct Matrix
  9. {
  10. long long a[53][53];
  11. Matrix()
  12. {
  13. memset(a, 0, sizeof(a));
  14. for(int i=1; i<=52; i++)
  15. {
  16. a[i][i]=1;
  17. }
  18. }
  19. };
  20. Matrix operator * (const Matrix & m1, const Matrix & m2)
  21. {
  22. Matrix m;
  23. for(int i=1; i<=siz; i++)
  24. {
  25. for(int j=1; j<=siz; j++)
  26. {
  27. m.a[i][j]=0;
  28. for(int k=1; k<=siz; k++)
  29. {
  30. m.a[i][j]=(m.a[i][j]+(m1.a[i][k]*m2.a[k][j])%mod)%mod;
  31. }
  32. }
  33. }
  34. return m;
  35. }
  36. Matrix quick_pow(Matrix base, long long pow)
  37. {
  38. Matrix A;
  39. while(pow)
  40. {
  41. if(pow&1)
  42. {
  43. A=A*base;
  44. }
  45. base=base*base;
  46. pow>>=1;
  47. }
  48. return A;
  49. }
  50. int main()
  51. {
  52. long long t;
  53. memset(C,0,sizeof(C));
  54. C[0][0]=1;
  55. C[1][0]=C[1][1]=1;
  56. for(int i=2; i<=50; i++)
  57. {
  58. for(int j=0; j<=i; j++)
  59. {
  60. if (j==0)
  61. {
  62. C[i][j]=1;
  63. }
  64. else
  65. {
  66. C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
  67. }
  68. }
  69. }
  70. scanf("%lld",&t);
  71. for (long long cas=1; cas<=t; cas++)
  72. {
  73. scanf("%lld%lld",&n,&k);
  74. siz=k+2;
  75. Matrix tran;
  76. memset(tran.a, 0, sizeof(tran.a));
  77. for(int i=1; i<=k+1; i++)
  78. {
  79. for(int j=1; j<=k+1; j++)
  80. {
  81. if(i<=j)
  82. {
  83. tran.a[i][j]=C[k+1-i][j-i];
  84. }
  85. }
  86. }
  87. for(int i=1; i<=k+1; i++)
  88. {
  89. tran.a[k+2][i]=C[k][i-1];
  90. }
  91. tran.a[k+2][k+2]=1;
  92. Matrix ans=quick_pow(tran,n-1);
  93. long long ans1=0;
  94. for(int i=1; i<=k+2; i++)
  95. {
  96. ans1=(ans1+ans.a[k+2][i])%mod;
  97. }
  98. printf("Case %lld: %lld\n",cas,ans1);
  99. }
  100. return 0;
  101. }

Problem F:Diablo

题意:给一个动态的序列,每次询问序列中第k个元素是啥,询问完以后,就删除这个元素,同时可以在结尾添加元素,如果当前位置没有元素,就输出“none”。

题解:区间修改+区间询问+单点修改的线段树。一开始毫无头绪,好在mzjj和js提示了许多。。总的来说树上维护的东西是当前区间内还有多少个元素没被删除,这样当询问到某一棵子树的时候,如果左子树的元素个数大于k,那么元素必定在左子树当中,否则就在右子树当中,在左子树当中固然好,就是左子树区间内第k个,在右子树的话就应该是第k减去左子树元素个数个,同时在叶子结点维护元素值。

参考代码:

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cstdlib>
  4. #include<cstring>
  5. #include<cmath>
  6. #include<algorithm>
  7. using namespace std;
  8. int num[800010],id[800010],ans;
  9. void pushup(int rt)
  10. {
  11. num[rt]=num[rt*2]+num[rt*2+1];
  12. }
  13. void build(int l,int r,int rt)
  14. {
  15. num[rt]=0;
  16. id[rt]=-1;
  17. if (l==r) return;
  18. int mid=(l+r)/2;
  19. build(l,mid,rt*2);
  20. build(mid+1,r,rt*2+1);
  21. }
  22. void update(int x,int c,int l,int r,int rt)
  23. {
  24. if (l==r)
  25. {
  26. num[rt]=1;
  27. id[rt]=c;
  28. return;
  29. }
  30. int mid=(l+r)/2;
  31. if (x<=mid) update(x,c,l,mid,rt*2);
  32. else update(x,c,mid+1,r,rt*2+1);
  33. pushup(rt);
  34. }
  35. void query(int k, int l, int r, int rt)
  36. {
  37. num[rt]-=1;
  38. if (l==r)
  39. {
  40. ans=id[rt];
  41. id[rt]=-1;
  42. return;
  43. }
  44. int mid=(l+r)/2;
  45. if (num[rt*2]>=k) query(k,l,mid,rt*2);
  46. else
  47. {
  48. k-=num[rt*2];
  49. query(k,mid+1,r,rt*2+1);
  50. }
  51. }
  52. int main()
  53. {
  54. int t,icase=1;;
  55. scanf("%d",&t);
  56. while(t--)
  57. {
  58. int n,m,sum;
  59. scanf("%d%d",&n,&m);
  60. sum=n+m;
  61. build(1,sum,1);
  62. printf("Case %d:\n",icase++);
  63. for (int i=1; i<=n; i++)
  64. {
  65. int x;
  66. scanf("%d",&x);
  67. update(i,x,1,sum,1);
  68. }
  69. while (m--)
  70. {
  71. char s[2];
  72. int x;
  73. scanf("%s%d",s,&x);
  74. if (s[0]=='a')
  75. {
  76. n+=1;
  77. update(n,x,1,sum,1);
  78. }
  79. else
  80. {
  81. query(x,1,sum,1);
  82. if (ans==-1) printf("none\n");
  83. else printf("%d\n",ans);
  84. }
  85. }
  86. }
  87. return 0;
  88. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注