zoukankan      html  css  js  c++  java
  • [cf1326F]Wise Men

    对答案序列求一个高维后缀和,再通过差分将其解出,后者复杂度为$o(n2^{n})$

    对于求后缀和后的结果,即01序列仅要求1处有边(不要求0处没有边),那么也即要求将原图划分为若干条长度给定且没有公共点的链

    不妨先去枚举链的长度,假设为${l_{1},l_{2},...,l_{m}}$,要求满足$l_{1}le l_{2}le ...le l_{m}$且$sum_{i=1}^{m}l_{i}=n$,记其对应的方案数为$P(n)$即为A000041,也即有$P(18)=385$

    下面,问题即要求出对应的方案数,并加到需要贡献的状态上——

    状压dp求出$f_{S}$表示$S$中的点构成链的排列数,时间复杂度为$o(n^{2}2^{n})$

    构造$g_{i,S}=egin{cases}0&(|S| e i)\f_{S}&(|S|=i)end{cases}$,不难发现方案数即为$(igcirc_{i=1}^{m}g_{l_{i}})_{V}$(其中$circ$为或卷积,$V$为点集),先预处理出$g_{i}$做FWT的结果,再$o(2^{n})$求出乘积在$V$处的值,时间复杂度为$o(n^{2}2^{n}+P(n)2^{n})$

    对于其有贡献的状态,即将${l_{i}}$重新排列后不同的序列,注意到每一个状态最多统计一次,因此暴力枚举所有排列(不重复)的复杂度也仅为$o(P(n)2^{n})$

    综上,总复杂度为$o(n^{2}2^{n}+P(n)2^{n})$,可以通过

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define N (1<<18)
     4 #define L 19
     5 #define ll long long
     6 vector<int>v;
     7 int n,cnt[N],vis[L];
     8 ll f[N][L],g[L][N],S[N],SS[L][N],ans[N];
     9 char s[L][L];
    10 void FWT(ll *a){
    11     for(int i=0;i<n;i++)
    12         for(int j=0;j<(1<<n);j++)
    13             if (j&(1<<i))a[j]+=a[j^(1<<i)];
    14 }
    15 void get_per(int k,int S,ll s){
    16     if (k==v.size()){
    17         ans[S]+=s;
    18         return;
    19     }
    20     int lst=0;
    21     for(int i=0;i<v.size();i++)
    22         if ((!vis[i])&&(lst!=v[i])){
    23             vis[i]=1,lst=v[i];
    24             get_per(k+1,((S<<v[i])|((1<<v[i]-1)-1)),s);
    25             vis[i]=0;
    26         }
    27 }
    28 void dfs(int k,int lst){
    29     if (!k){
    30         ll s=0;
    31         for(int i=0;i<(1<<n);i++)
    32             if ((n-cnt[i])&1)s-=S[i];
    33             else s+=S[i];
    34         get_per(0,0,s);
    35         return;
    36     }
    37     memcpy(SS[k],S,sizeof(S));
    38     for(int i=lst;i<=k;i++){
    39         v.push_back(i);
    40         for(int j=0;j<(1<<n);j++)S[j]*=g[i][j];
    41         dfs(k-i,i);
    42         v.pop_back();
    43         memcpy(S,SS[k],sizeof(S));
    44     }
    45 }
    46 int main(){
    47     scanf("%d",&n);
    48     for(int i=0;i<n;i++)scanf("%s",s[i]);
    49     for(int i=0;i<(1<<n);i++)cnt[i]=cnt[i>>1]+(i&1);
    50     for(int i=0;i<n;i++)f[1<<i][i]=1;
    51     for(int i=1;i<(1<<n);i++)
    52         for(int j=0;j<n;j++)
    53             if (i&(1<<j)){
    54                 g[cnt[i]][i]+=f[i][j];
    55                 for(int k=0;k<n;k++)
    56                     if (((i&(1<<k))==0)&&(s[j][k]=='1'))f[i|(1<<k)][k]+=f[i][j]; 
    57             }
    58     for(int i=1;i<=n;i++)FWT(g[i]);
    59     for(int i=0;i<(1<<n);i++)S[i]=1;
    60     dfs(n,1);
    61     n--;
    62     for(int i=0;i<n;i++)
    63         for(int j=0;j<(1<<n);j++)
    64             if (j&(1<<i))ans[j^(1<<i)]-=ans[j];
    65     for(int i=0;i<(1<<n);i++)printf("%lld ",ans[i]);
    66     printf("
    ");
    67     return 0;
    68 } 
    View Code
  • 相关阅读:
    [IMX6]Android6.0移植和分析
    Android设计原则和设计模式
    Linux内核源码目录
    Android源码博客目录
    Android应用博客目录
    imx6的kernel3.4.15启动流程
    dd命令
    shell
    i.mx6 Android5.1.1 build解析
    git总结
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/15226409.html
Copyright © 2011-2022 走看看