Oier们的镜子(mirror)
题解:
这题真是把我坑的很惨。。
题目看了很久才看懂。。
然后刚开始又没看见每个只能匹配一个这种条件
#include <bits/stdc++.h> using namespace std; #define rint register int #define IL inline #define rep(i,h,t) for (rint i=h;i<=t;i++) #define dep(i,t,h) for (rint i=t;i>=h;i--) const int N=16; const int N2=1<<16; int n,f[N][N2],g[N2],q[N],C[25][25],a[N]; const int mo=1000000007; int main() { freopen("1.in","r",stdin); freopen("1.out","w",stdout); ios::sync_with_stdio(false); cin>>n; rep(i,1,n) cin>>a[i]; sort(a+1,a+n+1); int lst=0; rep(i,1,20) rep(j,0,i) if (j==i||j==0) C[i][j]=1; else C[i][j]=C[i-1][j]+C[i-1][j-1]; f[0][0]=1; rep(i,1,n) { if (a[i]==a[i+1]) continue; rep(k,0,i-lst) { rint now=0; rep(j,1,k) now^=1<<(i-j); rint l=(1<<lst)-1; rep(j,0,l) if (f[lst][j]) { int ans1=C[i-lst][k]; int cnt=0,ans=0; rep(k,0,lst-1) if ((j>>k)&1) q[++cnt]=k+1; int l2=(1<<cnt)-1,cnt2=0,num=0; rep(k1,1,l2) { if (k1>>(cnt2+1)) cnt2++; g[k1]=g[k1^(1<<cnt2)]+a[q[cnt2+1]]; if (g[k1]==a[i]) num++; } ans1=1ll*ans1*f[lst][j]%mo; ans=1ll*(num+k)%mo; rep(p,1,i-lst-k) ans1=1ll*ans1*ans%mo; f[i][j^now]=ans1; } } lst=i; } int ans=0; rep(i,0,(1<<n)-1) ans=(ans+f[n][i])%mo; cout<<ans<<endl; return 0; }
然后又思考怎么处理相同元素思考了比较久
我自己写了一种特判相同元素的方法。。。非常复杂。。。(还是看错题目的),之后就没改了
大致就是枚举这些元素里哪些是镜子,哪些是由东西组合的,然后再乘组合数再乱搞。。
首先这道题目状压dp是比较显然的
排序也是比较显然的
然后唯一的问题在于相同元素怎么办
有一个非常巧妙的办法就是
当f[i][j]通过相同元素转移,那么要把这个东西乘二
为什么呢,我们可以这么理解,如果你要把右边的那个东西当镜子,左边的当元素
那么和左边当镜子,右边当元素方案数是等价的
因为由于这道题的特性每个元素只能对应一个,所以对于这两个元素,有关联的只有互相
// luogu-judger-enable-o2 #include <bits/stdc++.h> using namespace std; #define ll long long #define rint register int #define IL inline #define rep(i,h,t) for (rint i=h;i<=t;i++) #define dep(i,t,h) for (rint i=t;i>=h;i--) #define lowbit(x) (x&(-x)) const int N=16; const int N2=1<<15; int n,a[N],b[N2],sum[N2],f[N][N2]; const int mo=1e9+7; void js(int &x,int y) { x+=y; x%=mo; } int main() { ios::sync_with_stdio(false); cin>>n; rep(i,1,n) cin>>a[i]; sort(a+1,a+n+1); rep(i,1,n) b[1<<(i-1)]=a[i]; int l=(1<<n)-1; f[0][0]=1; rep(i,1,l) sum[i]=sum[i-lowbit(i)]+b[lowbit(i)]; rep(i,1,n) { rep(j,0,l) if (f[i-1][j]) { js(f[i][j|(1<<(i-1))],f[i-1][j]); for(rint k=j;k;k=(k-1)&j) if (sum[k]==a[i]) { js(f[i][j^k],f[i-1][j]); if (!(k-lowbit(k))) js(f[i][j^k],f[i-1][j]); } } } int ans=0; rep(i,0,l) js(ans,f[n][i]); cout<<ans<<endl; return 0; }
同学给了我一种新的方法。。
我们可以比较暴力的做
每次枚举一个数,然后枚举子集可以用哪些东西构成
记录一下用了几组,最后除掉就行了
7*3^n并不能过
然后可以用fwt优化