[2734]集合选数

[2734]集合选数


不太知道怎么想出来这种东西啊

我们考虑这样的矩阵:

x/y     1    2    4    8   16   32  ... 
  1   1*1  1*2  1*4  1*8 1*16 1*32  ...
  3   3*1  3*2  3*4  ...  ...  ...  ...
  9   9*1  ...  ...  ...  ...  ...  ...
 27  27*1  ...  ...  ...  ...  ...  ...
 81  81*1  ...  ...  ...  ...  ...  ...
...   ...  ...  ...  ...  ...  ...  ...

我们发现,如果要一个合法的子集,所选的数就应该是矩阵中互不相邻的数。

然后我们要把他们都乘上一个数,易得那个数的性质是 %2>0 && %3>0 然后矩阵之间是相互独立的。

每一个块可以状压,我们就可以统计答案了。

  • 代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll mod=1000000001;
const int N=1e5+5;
bool vis[N];
int prime[N],cnt;

int n;
ll f[2][4100];
unsigned long long RES=1;

inline bool chk(int status){
    for(int i=0;i<=13;i++){
        if((1<<i)>=status)break;
        if(((status>>i)&1)&&((status>>(i+1))&1))return false;
    }
    return true;
}

inline void solve(int sum){
    memset(f,0,sizeof(f));
    int pw1=1,P=0;
    for(P=0;pw1<=sum;P++,pw1*=3);
    int pw2=1,L=0;
    for(L=0;pw2<=sum;L++,pw2*=2);
    int pst=1,nw=0;
    f[nw][0]=1;
    int pw=1;
    for(int i=0;i<L;i++){
        swap(nw,pst);
        memset(f[nw],0,sizeof(f[nw]));
        int tp=0,w=pw;
        for(;w<=sum;w*=3,tp++);
        for(int Lst=0;Lst<1<<P;Lst++)if(f[pst][Lst]){
            for(int Cst=0;Cst<1<<tp;Cst++)if(chk(Cst)&&(Cst&Lst)==0){
                f[nw][Cst]=(f[nw][Cst]+f[pst][Lst])%mod;
            }
        }
        pw<<=1;
    }
    ll ans=0;
    for(int i=0;i<1<<P;++i){
        ans=(ans+f[nw][i])%mod;
    }
    RES=RES*ans%mod;
}

int main()
{
    scanf("%d",&n);
    prime[0]=1;
    for(int i=1;i<=n;i++)if( i%2 && i%3 ){
        int sum=n/i;
        solve(sum);
    }
    printf("%lld\n",RES);
}

猜你喜欢

转载自blog.csdn.net/qq_35923186/article/details/83313930