[关闭]
@ysner 2018-06-17T17:33:35.000000Z 字数 2297 阅读 1888

惑疑的凯小

DP


题面

现有个砝码,重量分别为太好吃了,于是吃掉了其中个砝码。
现在想知道,他在剩余的砝码中随机选取一些砝码(不能不选),正好称出的重量的方案数?
但他要我们输出的是答案 除以 吃掉砝码的方案数,并对取模。

解析

算法

显然可以设表示前个数中随便取数后和为的方案数。
则枚举,可得转移方程


复杂度最坏为

考场龟速算法

枚举去掉哪些砝码。
然后使用算法即可。
使用快速幂和费马小定理(要求为质数)


就可以处理答案了。
复杂度,理论会炸,但过了???

  1. #include<iostream>
  2. #include<cmath>
  3. #include<cstring>
  4. #include<cstdio>
  5. #include<cstdlib>
  6. #include<algorithm>
  7. #define ll unsigned long long
  8. #define re register
  9. #define il inline
  10. #define fp(i,a,b) for(re int i=a;i<=b;i++)
  11. #define fq(i,a,b) for(re int i=a;i>=b;i--)
  12. using namespace std;
  13. const int N=250,mod=6249433;
  14. int n,m,k,a[N],dp[N][N*100],pr[N],vis[N];
  15. ll ans;
  16. il ll gi()
  17. {
  18. re ll x=0,t=1;
  19. re char ch=getchar();
  20. while((ch<'0'||ch>'9')&&ch!='-') ch=getchar();
  21. if(ch=='-') t=-1,ch=getchar();
  22. while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
  23. return x*t;
  24. }
  25. il void wri(re ll x)
  26. {
  27. if(x<0) putchar('-'),x=-x;
  28. if(x>9) wri(x/10);
  29. putchar(x%10+'0');
  30. }
  31. il ll check(re ll x)
  32. {
  33. while(x>=mod) x-=mod;
  34. return x;
  35. }
  36. il ll ksm(re ll x,re ll n)
  37. {
  38. re ll S=1,T=x;
  39. while(n)
  40. {
  41. if(n&1) S=check(S*T);
  42. T=check(T*T);
  43. n>>=1;
  44. }
  45. return S;
  46. }
  47. il void solve()
  48. {
  49. //fp(i,1,n) printf("%d ",pr[i]);puts("");
  50. fp(i,1,k) fp(j,0,n) dp[j][i]=0;
  51. fp(i,1,n) dp[i][a[i]]=1;
  52. fp(i,1,k)
  53. fp(j,1,n)
  54. if(!vis[j])
  55. {
  56. dp[j][i+a[j]]=check(dp[j][i+a[j]]+dp[pr[j]][i]);
  57. dp[j][i]=check(dp[j][i]+dp[pr[j]][i]);
  58. }
  59. re int ysn=n;while(vis[ysn]&&ysn) --ysn;
  60. ans=check(ans+dp[ysn][k]);
  61. }
  62. il void dfs(re int x,re int tot)
  63. {
  64. if(tot<0) return;
  65. if(x==n+1) {if(!tot) solve();return;}
  66. fp(i,0,1)
  67. if(i) vis[x]=1,pr[x+1]=pr[x],dfs(x+1,tot-1),vis[x]=0,pr[x+1]=x;
  68. else
  69. {
  70. if(a[x]>k) pr[x+1]=pr[x];
  71. dfs(x+1,tot);
  72. }
  73. }
  74. il ll jc(re ll s,re ll e,re int flag)
  75. {
  76. re ll pzy=1;
  77. fp(i,s,e) pzy=check(pzy*i);
  78. if(flag) pzy=ksm(pzy,mod-2);
  79. return pzy;
  80. }
  81. int main()
  82. {
  83. freopen("htam.in","r",stdin);
  84. freopen("htam.out","w",stdout);
  85. re int T=gi();
  86. while(T--)
  87. {
  88. n=gi()^ans,m=gi()^ans,k=gi()^ans;ans=0;
  89. if(k==0) {puts("0");continue;}
  90. fp(i,1,n) a[i]=gi(),pr[i]=i-1;
  91. dfs(1,m);
  92. re ll eat=1;
  93. if(m) eat=check(jc(1,n-m,0)*jc(m+1,n,1));
  94. //printf("%llu %llu\n",eat,ans);
  95. ans=check(ans*eat);
  96. wri(ans);putchar('\n');
  97. }
  98. fclose(stdin);
  99. fclose(stdout);
  100. return 0;
  101. }

考场感想:

贼快算法

枚举每个数取不取,如果取了个数,取了的数和为,就会生成个合法方案(剩下个数有个被吃了)。
复杂度叹为观止。(其实我考场上也想到过。。。)

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注