[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);
}