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优化

posted @ 2018-08-28 23:31  尹吴潇  阅读(224)  评论(0编辑  收藏  举报