标签:
Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)
我第一发TLE的NAIVE写法:
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int N{20}; int T, n, m, p; int a[N]; LL dp[1<<20]; int calc(int s){ int res=0; for(int i=0; i<m; i++) if(s&1<<i) res+=a[i]; return res; } int ones(int s){ int res=0; for(int i=0; i<n+m; i++) res+=bool(s&1<<i); return res; } int r(int s){ int x=0, y=0; for(int i=0; i<(n+m); i++) if(s&1<<i){ x++; if(i>=m) y++; } return 2*y+1-x; } // 33554432 int main(){ LL f[N]{1}; for(int i=1; i<N; i++) f[i]=f[i-1]*i; for(cin>>T; T--; ){ cin>>p>>n>>m; for(int i=0; i<m; i++) cin>>a[i]; int tot=m+n; memset(dp, 0, sizeof(dp)); dp[0]=1; for(int s=0; s<1<<tot; s++) if(dp[s] &&r(s)>0) for(int j=0; j<tot; j++) if(!(s&1<<j)) dp[s|1<<j]+=dp[s]; LL res=0; int full=(1<<tot)-1; for(int s=0; s<1<<tot; s++) if(calc(s)>=p && (r(s)==0 || s==full)) res+=dp[s]*f[tot-ones(s)]; // cout<<res<<endl; LL gcd=__gcd(res, f[tot]); printf("%lld/%lld\n", res/gcd, f[tot]/gcd); } }
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int N{1<<5}; int T, n, m, p; int a[N], ones[1<<20]; LL dp[1<<20], f[N]{1}; inline int calc(int s){ int res=0; for(int i=0; i<m; i++) if(s&1<<i) res+=a[i]; return res; } inline int r(int s){ int res=0; for(int i=0; i<m; i++) res+=bool(s&1<<i); // return 2*(ones[s]-res)+1-ones[s]; return ones[s]-(res<<1)+1; } // 33554432 int main(){ for(int i=0; i<1<<20; i++) for(int j=0; j<20; j++) if(i&1<<j) ones[i]++; for(int i=1; i<N; i++) f[i]=f[i-1]*i; for(scanf("%d", &T); T--; ){ scanf("%d%d%d", &p, &n, &m); for(int i=0; i<m; i++) scanf("%d", a+i); // LL res=0; int tot=m+n; LL res=0, full=(1<<tot)-1; if(calc(full)>=p){ memset(dp, 0, sizeof(dp)); dp[0]=1; for(int s=0; s<1<<tot; s++) if(dp[s]) if(r(s)==0 || s==full){ if(calc(s)>=p) res+=dp[s]*f[tot-ones[s]]; } else{ for(int j=0; j<tot; j++) if(!(s&1<<j)) dp[s|1<<j]+=dp[s]; } } LL gcd=__gcd(res, f[tot]); printf("%lld/%lld\n", res/gcd, f[tot]/gcd); } }
这个写法赛后在题库中AC了, 跑了907ms...
AC的姿势:
#include <bits/stdc++.h> using namespace std; typedef long long LL; const int N{1<<5}; int T, n, m, p; int a[N], ones[1<<20]; LL dp[1<<20], f[N]{1}; inline int calc(int s){ int res=0; for(int i=0; i<m; i++) if(s&1<<i) res+=a[i]; return res; } inline int r(int s){ int res=0; for(int i=0; i<m; i++) res+=bool(s&1<<i); // return 2*(ones[s]-res)+1-ones[s]; return ones[s]-(res<<1)+1; } // 33554432 int main(){ for(int i=0; i<1<<20; i++) for(int j=0; j<20; j++) if(i&1<<j) ones[i]++; for(int i=1; i<N; i++) f[i]=f[i-1]*i; for(scanf("%d", &T); T--; ){ scanf("%d%d%d", &p, &n, &m); for(int i=0; i<m; i++) scanf("%d", a+i); // LL res=0; int tot=m+n; LL res=0, full=(1<<tot)-1; if(calc(full)>=p){ memset(dp, 0, sizeof(dp)); dp[0]=1; for(int s=0; s<1<<tot; s++) if(dp[s]) if(calc(s)>=p) res+=dp[s]*f[tot-ones[s]]; else if(r(s)>0) for(int j=0; j<tot; j++) if(!(s&1<<j)) dp[s|1<<j]+=dp[s]; } LL gcd=__gcd(res, f[tot]); printf("%lld/%lld\n", res/gcd, f[tot]/gcd); } }
这个跑了358ms.
Conclusion:
1. 剪枝
2. 预处理$\text{ones}$表, $\text{ones}[i]$表示$i$的二进制表达式中$1$的个数.
这题应该还有复杂度更优的做法, 之后再补充.
标签:
原文地址:http://www.cnblogs.com/Patt/p/5754266.html