test20181019 B君的第二題
阿新 • • 發佈:2018-11-10
題意
分析
快速子集和變換以及快速超集和變換的裸題。
用\(f(s)\)表示集合s的方案數,初始化為輸入中s出現的次數。
- 做一遍快速子集和變換,此時f(s)表示s及其子集在輸入中出現的次數。
- 對所有f(s)所表示的數兩兩組合,此時f(s)表示生成s及其子集的方案數。
- 做一遍快速子集差變換,此時f(s)表示生成s的方案數。
- 做一遍快速超集和變換,此時f(s)表示生成s及其超集的方案數。
時間複雜度\(O(n \cdot k)\)
淺談FST
感覺就是對每一個二進位制位縱向更新,這樣就不會算重,時間複雜度\(O(s \cdot 2^s)\)
程式碼
#include<cstdlib> #include<cstdio> #include<cmath> #include<cstring> #include<iostream> #include<string> #include<vector> #include<list> #include<deque> #include<stack> #include<queue> #include<map> #include<set> #include<bitset> #include<algorithm> #include<complex> #define rg register #define il inline #define co const #pragma GCC optimize ("O0") using namespace std; template<class T> il T read() { rg T data=0; rg int w=1; rg char ch=getchar(); while(!isdigit(ch)) { if(ch=='-') w=-1; ch=getchar(); } while(isdigit(ch)) data=10*data+ch-'0',ch=getchar(); return data*w; } template<class T> il T read(rg T&x) { return x=read<T>(); } typedef long long ll; const int INF=0x7fffffff; const int MAXN=1<<20|7; ll f[MAXN]; int main() { freopen("lhasa.in","r",stdin); freopen("lhasa.out","w",stdout); rg int n,k; read(n);read(k); for(rg int i=1;i<=n;++i) { ++f[read<int>()]; } for(rg int i=0;i<k;++i) // 逐位遞推 for(rg int j=0;j<1<<k;++j) if(j >> i & 1) { f[j] += f[j ^ (1 << i)]; } for(rg int i=0;i<1<<k;++i) // 組合 { f[i]=f[i]*(f[i]-1)/2; } for(rg int i=0;i<k;++i) // 減去組合成自己的組合 for(rg int j=0;j<1<<k;++j) if(j >> i & 1) { f[j] -= f[j ^ (1 << i)]; } for(rg int i=0;i<k;++i) // 加上超集的方案數 for(rg int j=0;j<1<<k;++j) if(j >> i & 1) { f[j ^ (1 << i)] += f[j]; } for(rg int i=0;i<1<<k;++i) { printf("%lld\n",f[i]); } // fclose(stdin); // fclose(stdout); return 0; }