[关闭]
@y20070316 2017-04-24T06:25:59.000000Z 字数 2263 阅读 1168

51Nod 1386 - 双马尾机器人

题目精选 平衡规划 状压dp


题意

      给定 ,我们要在 中选择若干的数,每一种选择的方案被称为选数方案。
      我们定义一种选数方案是合法的,当且仅当 没有被选,且任意两个选的数互质。
      我们定义一种选数方案是极大的,当且仅当它是合法的,且不能再从剩下的数中选择任意一个,或者选的是
      求极大的选数方案的最小的选的个数。


分析

      考虑一下怎样的选数方案是极大的。也就是我们要选1,以及 中的每个质数都要在我们选择的数中出现。我们要考虑满足上述要求的情况下选最少的数。
      对于 的质数,只有17个,我们考虑通过状态压缩进行记录。对于 的质数,每个数最多只有一个,我们根据这个质数对所有的数进行分类。然后考虑状压dp。
      设 表示当前弄到了第个大质数,小质数的填充情况为 的方案数。
      总之它是一种平衡规划,对于比较小的质数直接状压,对于比较大的就记录下来,按照它来分类转移。

      注意要把大质数个数和n给均摊下来。每个数按照对应的大质数分类。把 变成

实现

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. #define F(i,a,b) for (int i=(a);i<=(b);i++)
  4. #define D(i,a,b) for (int i=(a);i>=(b);i--)
  5. #define fore(v,u) for (vector<int>::iterator v=g[u].begin();v!=g[u].end();v++)
  6. #define LL long long
  7. #define LD long double
  8. LL rd(void) {
  9. LL x=0,f=1; char c=getchar();
  10. for (;!isdigit(c);c=getchar()) if (c=='-') f=-1;
  11. for (;isdigit(c);c=getchar()) x=x*10+c-'0';
  12. return x*f;
  13. }
  14. char rdc(void) {
  15. char c=getchar();
  16. while (!isalpha(c))
  17. c=getchar();
  18. return c;
  19. }
  20. const int M_N=1024;
  21. const int N=1000;
  22. int pri[M_N],vis[M_N],tot;
  23. int num[M_N];
  24. int big_cnt,kd[M_N],type[M_N][M_N];
  25. const int M_ALL=2048;
  26. const int M_BIG=170;
  27. const int small_cnt=11;
  28. const int all=(1<<small_cnt)-1;
  29. const int INF=0x7fffffff>>1;
  30. int f[M_BIG][M_ALL];
  31. int main(void) {
  32. #ifndef ONLINE_JUDGE
  33. freopen("sdchr.in","r",stdin);
  34. freopen("sdchr.out","w",stdout);
  35. #endif
  36. vis[1]=1;
  37. F(i,2,N) {
  38. if (!vis[i]) pri[++tot]=i;
  39. F(j,1,tot) {
  40. if (i*pri[j]>N) break;
  41. vis[i*pri[j]]=1;
  42. if (i%pri[j]==0) break;
  43. }
  44. }
  45. F(i,1,N) {
  46. int c=0;
  47. F(j,1,small_cnt)
  48. if (i%pri[j]==0)
  49. c|=(1<<(j-1));
  50. num[i]=c;
  51. }
  52. F(i,1,N) F(j,small_cnt+1,tot) if (i%pri[j]==0) kd[i]=j-small_cnt;
  53. F(i,1,N) type[kd[i]][++type[kd[i]][0]]=i;
  54. int nT=rd();
  55. F(c,1,nT) {
  56. int n=rd(),k=rd();
  57. big_cnt=small_cnt; while (big_cnt+1<=tot&&pri[big_cnt+1]<=n) big_cnt++; big_cnt-=small_cnt;
  58. F(t,0,big_cnt) F(i,0,all) f[t][i]=INF;
  59. f[0][0]=0;
  60. F(i,0,all) if (f[0][i]!=INF)
  61. F(now,1,type[0][0]) {
  62. int j=type[0][now];
  63. if (j<=n&&j!=k&&!(i&num[j]))
  64. f[0][i|num[j]]=min(f[0][i|num[j]],f[0][i]+1);
  65. }
  66. if (pri[small_cnt+1]>n) {
  67. int star=small_cnt;
  68. if (pri[star]>n) {
  69. while (star-1>0&&pri[star-1]>n)
  70. star--;
  71. star--;
  72. }
  73. printf("Case #%d: %d\n",c,f[0][(1<<star)-1]+(k!=1));
  74. continue;
  75. }
  76. F(t,1,big_cnt)
  77. F(i,0,all) if (f[t-1][i]!=INF)
  78. F(now,1,type[t][0]) {
  79. int j=type[t][now];
  80. if (j<=n&&j!=k&&!(i&num[j]))
  81. f[t][i|num[j]]=min(f[t][i|num[j]],f[t-1][i]+1);
  82. }
  83. printf("Case #%d: %d\n",c,f[big_cnt][all]+(k!=1));
  84. }
  85. return 0;
  86. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注