BZOJ4816 [SDOI2017]数字表格

Address


Solution

  • 莫比乌斯反演套路题。
  • i = 1 n i = 1 m f [ ( i , j ) ] \prod \limits_{i = 1}^{n} \prod \limits_{i = 1}^{m} f[(i, j)]
  • 考虑枚举 t = ( i , j ) t = (i, j) ,得:
    i = 1 n i = 1 m f [ ( i , j ) ] \prod \limits_{i = 1}^{n} \prod \limits_{i = 1}^{m} f[(i, j)] = t = 1 min { n , m } f [ t ] i = 1 n j = 1 m [ ( i , j ) = t ] =\prod \limits_{t = 1}^{\min\{n, m\}} f[t] ^{\sum\limits_{i = 1}^{n} \sum\limits_{j = 1}^{m}[(i, j) =t]} = t = 1 min { n , m } f [ t ] i = 1 n t j = 1 m t [ ( i , j ) = 1 ] = \prod\limits_{t = 1}^{\min\{n, m\}} f[t] ^{\sum \limits_{i = 1}^{\lfloor \frac{n}{t} \rfloor} \sum \limits_{j = 1}^{\lfloor \frac{m}{t}\rfloor} [(i, j) = 1]} = t = 1 min { n , m } f [ t ] i = 1 n t j = 1 m t d ( i , j ) μ ( d ) = \prod \limits_{t = 1}^{\min\{n, m\}} f[t] ^ {\sum \limits_{i = 1}^{\lfloor \frac{n}{t} \rfloor}\sum\limits_{j = 1}^{\lfloor \frac{m}{t} \rfloor} \sum\limits_{d | (i, j)} \mu(d)} = t = 1 min { n , m } f [ t ] d = 1 min { n , m } t μ ( d ) n t d m t d = \prod \limits_{t = 1}^{\min\{n, m\}} f[t] ^{\sum\limits_{d = 1}^{\lfloor \frac{\min\{n, m\}}{t}\rfloor}\mu(d)\lfloor\frac{n}{td}\rfloor \lfloor \frac{m}{td}\rfloor}
  • 考虑枚举 T = t d T = td
    = t = 1 min { n , m } f [ t ] t T μ ( T t ) n T m T = \prod \limits_{t = 1}^{\min\{n, m\}} f[t] ^{\sum \limits_{t | T} \mu(\frac{T}{t})\lfloor \frac{n}{T} \rfloor \lfloor \frac{m}{T} \rfloor}
  • 预处理 μ ( x ) , f ( x ) \mu(x), f(x) ,直接计算上面的式子,即可做到每组数据 O ( n log n ) O(n \log n) 的复杂度,可通过 60% 的数据。
  • 考虑把 T T 提到最外面,与 n , m n, m 无关的项提出来预处理,
    = T = 1 min { n , m } ( t T f [ t ] μ ( T t ) ) n T m T = \prod \limits_{T = 1}^{\min\{n, m\}}(\prod \limits_{t | T}f[t]^{\mu(\frac{T}{t})})^{\lfloor \frac{n}{T} \rfloor \lfloor \frac{m}{T} \rfloor}
  • g [ T ] = t T f [ t ] μ ( T t ) g[T] = \prod \limits_{t | T}f[t]^{\mu(\frac{T}{t})} ,因为 μ \mu 的取值只有 1 , 0 , 1 -1, 0, 1 ,预处理 f f 的逆元即可做到 O ( n log n ) O(n \log n) 预处理出 g g
  • 每组数据对 T T 整除分块,预处理 g g 的前缀积及其逆元,并根据欧拉定理对指数模 ( 1 0 9 + 6 ) (10^9 + 6) 减小常数,即可做到每组数据 O ( n log ( 1 0 9 + 5 ) ) O(\sqrt{n} \log(10^9 + 5)) 的复杂度。
  • 因此总的时间复杂度 O ( n log ( 1 0 9 + 7 ) + 1000 n log ( 1 0 9 + 5 ) ) O(n \log (10^9+7) + 1000 \sqrt{n} \log (10^9 + 5))

#include <algorithm>
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <vector>
#include <cctype>
#include <cmath>
#include <ctime>

template <class T>
inline void read(T &res)
{
	char ch; bool flag = false; res = 0;
	while (ch = getchar(), !isdigit(ch) && ch != '-');
	ch == '-' ? flag = true : res = ch ^ 48;
	while (ch = getchar(), isdigit(ch))
		res = res * 10 + ch - 48;
	flag ? res = -res : 0;
}

typedef long long ll;
const int N = 1e6 + 1;
const int mod = 1e9 + 7;
int pri[N], f[N], inv_f[N], g[N], inv_g[N], miu[N];
int T, n, m, pr, ans;
bool vis[N];

template <class T>
inline void put(T x)
{
	if (x > 9) put(x / 10);
	putchar(x % 10 + 48);
}

inline void add(int &x, int y)
{
	x += y;
	x >= mod ? x -= mod : 0;
}

inline int ksm(int x, int k)
{
	int res = 1;
	while (k)
	{
		if (k & 1) res = 1ll * res * x % mod;
		x = 1ll * x * x % mod; k >>= 1;
	}
	return res;
}

template <class T>
inline T Min(T x, T y) {return x < y ? x : y;}

int main()
{
	f[0] = 0; f[1] = 1;
	for (int i = 2; i < N; ++i)
		f[i] = f[i - 1], add(f[i], f[i - 2]);
	for (int i = 1; i < N; ++i)
		inv_f[i] = ksm(f[i], mod - 2);
	
	miu[1] = 1;
	for (int i = 2; i < N; ++i)
	{
		if (!vis[i])
			pri[++pr] = i, miu[i] = -1;
		for (int j = 1; j <= pr && 1ll * pri[j] * i < N; ++j)
		{
			int tmp = pri[j] * i;
			vis[tmp] = true;
			if (i % pri[j] == 0) 
			{
				miu[tmp] = 0;
				break;
			}
			miu[tmp] = -miu[i];
		}
	}
	for (int i = 0; i < N; ++i)
		g[i] = 1;
	for (int i = 1; i < N; ++i)
		for (int j = i, cnt = 1; j < N; j += i, ++cnt)
		{
			int t = miu[cnt];
			if (!t) continue;
			g[j] = 1ll * g[j] * (t == 1 ? f[i] : inv_f[i]) % mod;
		}
	for (int i = 1; i < N; ++i)
		g[i] = 1ll * g[i - 1] * g[i] % mod;
	for (int i = 0; i < N; ++i)
		inv_g[i] = ksm(g[i], mod - 2);
	read(T);
	while (T--)
	{
		read(n); read(m);
		if (n > m) std::swap(n, m);
		ans = 1;
		for (int i = 1, x; i <= n; i = x + 1)
		{
			x = Min(n / (n / i), m / (m / i));
			ans = 1ll * ans * ksm(1ll * g[x] * inv_g[i - 1] % mod, 1ll * (n / i) * (m / i) % (mod - 1)) % mod;
		}
		put(ans), putchar('\n');
	}
}
发布了104 篇原创文章 · 获赞 125 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/bzjr_Log_x/article/details/85720865
今日推荐