题解 P6274 [eJOI2017]六
搬运一下自己的博客
神仙思路。
~~对不起,爆搜真的能切题~~
状压套状压,对于每一个 $N$ 的因数,我们可以求出它带有哪些 $N$ 的质因数(注意,这里不要求质因数次数,因为两个数只要含有同一个质因数就不互质了)。然后用乘法原理优化一下就可以 $O(k2^k)$ 求出含有这些质因数的数的个数。
然后状压,三进制,$2^k-1$ 位,第 $i$ 位的值代表有多少个质因数情况为 $i$ 的。
这样可能不好理解,举个例子:
$N=2^2 \times 3^2 \times 5 \times 7$
所以 $k=4$ ,然后比如像 $84=2^2 \times 3 \times 7$ 很显然是 $N$ 的因数,此时质因数情况为 $1101$
然后记忆化搜索即可。
但是仍然需要优化,首先把 $3$ 进制变成 $4$ 进制更加好写,但是此时需要用两个 $unsigned \ \ long \ \ long$ 存,此时用 $map$ 又多一个 $log$ (虽然没多大事貌似),考虑使用 $hash$ ,就两位,还不用担心取模耗时间( $ull$ ),然后貌似就可以了
细节看代码:
#include#include #define ull unsigned long long #define maxn 101 #define maxN 20000002 #define mod 1000000007 inline long long read(){ long long r=0,f=0; char c; while(!isdigit(c=getchar()))f|=(c=='-'); while(isdigit(c))r=(r<<1)+(r<<3)+(c^48),c=getchar(); return f?-r:r; } int k,cs[maxn],cnt[maxn],rel[maxn][maxn]; long long n,m,p[maxn],f[maxN];//f尽量开大,hash冲突概率小一些 inline void add_cnt(long long x){ int zt=0; for(int i=0;i >(i<<1)):(y>>((i-32)<<1)))&3; } inline void add(ull &x,ull &y,int i){ i<32?x+=1ull<<(i<<1):y+=1ull<<((i-32)<<1); } long long solve(ull x,ull y){ ull hx=x*131+y;//hash hx%=maxN; if(f[hx])return f[hx]; long long ans=1; for(int i=1;i<(1< 1)cs[k]=1,p[k++]=m; for(int i=1;i<(1< >j)&1)cnt[i]*=cs[j]; } printf("%lld",(solve(0,0)-1+mod)%mod);//记得减1,因为不能不放数字 return 0; }