題解 2020.10.24 考試 T3 數列
阿新 • • 發佈:2020-10-25
題目大意
給出一個數 \(n\),你要構造一個數列,滿足裡面每個數都是 \(n\) 的因子,且每一個數與前面不互質的個數不超過 \(1\)。問有多少種合法方案。
保證 \(n\) 的不同質因子個數 \(\le 6\)。
思路
這個題不是很難,只是比較難寫。不過 \(\Theta(6\times 3^6)\) 的做法感覺比較有意思,但是我寫的是玄學時間複雜度的做法。
我們可以看出數列長度最大也就 \(12\),而且質因子個數也很少,不難想到狀壓 dp,我們發現這個狀壓 dp 完全沒有什麼難點,直接 \(f_{S,x}\) 表示當前狀態為 \(S\),已經填了 \(x\) 位的方案數。對於一個狀態,肯定是每個質因子的狀態組合起來,你發現重要的不過就是這個質因子出現了幾次,如果只出現一次是哪些質因子一起出現的。你把這個壓進狀態就好了。
似乎預處理了之後轉移可以更快,但是懶得了。
\(\texttt{Code}\)
#include <bits/stdc++.h> using namespace std; #define Int register int #define mod 1000000007 #define ll long long template <typename T> inline void read (T &t){t = 0;char c = getchar();int f = 1;while (c < '0' || c > '9'){if (c == '-') f = -f;c = getchar();}while (c >= '0' && c <= '9'){t = (t << 3) + (t << 1) + c - '0';c = getchar();} t *= f;} template <typename T,typename ... Args> inline void read (T &t,Args&... args){read (t);read (args...);} template <typename T> inline void write (T x){if (x < 0){x = -x;putchar ('-');}if (x > 9) write (x / 10);putchar (x % 10 + '0');} ll N; int cnt,yz[15],pw[15]; int mul (int a,int b){return 1ll * a * b % mod;} int dec (int a,int b){return a >= b ? a - b : a + mod - b;} int add (int a,int b){return a + b >= mod ? a + b - mod : a + b;} void Mul (int &a,int b){a = mul (a,b);} void Dec (int &a,int b){a = dec (a,b);} void Add (int &a,int b){a = add (a,b);} void Makeyz (ll n){ for (Int i = 2;1ll * i * i <= n;++ i){ if (n % i == 0){ yz[++ cnt] = i; while (n % i == 0) n /= i,pw[cnt] ++; } } if (n > 1) yz[++ cnt] = n,pw[cnt] = 1; } int f[1 << 19][15]; signed main(){ read (N),Makeyz (N); f[0][0] = 1;int ans = 0; for (Int x = 0;x < cnt * 2;++ x){ for (Int nowS = 0;nowS < (1 << cnt * 3);++ nowS){ if (!f[nowS][x]) continue; vector <int> unused,cho; bool used[12] = {}; for (Int i = 1;i <= cnt;++ i){ int k = nowS >> (i - 1) * 3 & 7; if (!k) unused.push_back (i); else if (k < 7 && !used[k]) cho.push_back (i),used[k] = 1; } int siz1 = unused.size(),siz2 = cho.size(); for (Int S = 0;S < (1 << siz1);++ S){ int kase = 1,S1 = 0,fir = 0; for (Int i = 0;i < siz1;++ i) if (S >> i & 1) fir = fir ? fir : unused[i],Mul (kase,pw[unused[i]]),S1 |= (1 << (unused[i] - 1) * 3) * fir; if (S) Add (f[nowS | S1][x + 1],mul (kase,f[nowS][x])); if (!cho.size()) continue; for (Int u : cho){ int k = nowS >> (u - 1) * 3 & 7,siz2 = 0; vector <int> uni; for (Int i = 1;i <= cnt;++ i) if ((nowS >> (i - 1) * 3 & 7) == k) uni.push_back (i); siz2 = uni.size(); for (Int choS = 1;choS < (1 << siz2);++ choS){ int newS = nowS | S1,fir = 0x7f7f7f7f,kase1 = 1; for (Int i = 0;i < siz2;++ i) if (choS >> i & 1) newS -= (1 << (uni[i] - 1) * 3) * (k - 7),Mul (kase1,pw[uni[i]]); else fir = min (fir,uni[i]); for (Int i = 0;i < siz2;++ i) if (!(choS >> i & 1)) newS -= (1 << (uni[i] - 1) * 3) * (k - fir); Add (f[newS][x + 1],mul (f[nowS][x],mul (kase,kase1))); } } } } } for (Int x = 1;x <= cnt * 2;++ x) for (Int nowS = 0;nowS < (1 << cnt * 3);++ nowS) Add (ans,f[nowS][x]); write (ans),putchar ('\n'); return 0; }