BZOJ4816 [SDOI2017]数字表格

58 篇文章 0 订阅

Address


Solution

  • 莫比乌斯反演套路题。
  • ∏ i = 1 n ∏ i = 1 m f [ ( i , j ) ] \prod \limits_{i = 1}^{n} \prod \limits_{i = 1}^{m} f[(i, j)] i=1ni=1mf[(i,j)]
  • 考虑枚举 t = ( 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)] i=1ni=1mf[(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=1min{n,m}f[t]i=1nj=1m[(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=1min{n,m}f[t]i=1tnj=1tm[(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=1min{n,m}f[t]i=1tnj=1tmd(i,j)μ(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=1min{n,m}f[t]d=1tmin{n,m}μ(d)tdntdm
  • 考虑枚举 T = t d T = td 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} =t=1min{n,m}f[t]tTμ(tT)TnTm
  • 预处理 μ ( x ) , f ( x ) \mu(x), f(x) μ(x),f(x),直接计算上面的式子,即可做到每组数据 O ( n log ⁡ n ) O(n \log n) O(nlogn) 的复杂度,可通过 60% 的数据。
  • 考虑把 T T T 提到最外面,与 n , m 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} =T=1min{n,m}(tTf[t]μ(tT))TnTm
  • g [ T ] = ∏ t ∣ T f [ t ] μ ( T t ) g[T] = \prod \limits_{t | T}f[t]^{\mu(\frac{T}{t})} g[T]=tTf[t]μ(tT),因为 μ \mu μ 的取值只有 − 1 , 0 , 1 -1, 0, 1 1,0,1,预处理 f f f 的逆元即可做到 O ( n log ⁡ n ) O(n \log n) O(nlogn) 预处理出 g g g
  • 每组数据对 T T T 整除分块,预处理 g g g 的前缀积及其逆元,并根据欧拉定理对指数模 ( 1 0 9 + 6 ) (10^9 + 6) (109+6) 减小常数,即可做到每组数据 O ( n log ⁡ ( 1 0 9 + 5 ) ) O(\sqrt{n} \log(10^9 + 5)) O(n log(109+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)) O(nlog(109+7)+1000n log(109+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');
	}
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值