bzoj 3309 反演

$n=p_1^{a_1}p_2^{a_2}…p_k^{a_k},p_i$为素数,定义$f(n)=max(a_1,a_2…,a_k)$。

给定a,b<=1e7求$\sum\limits_{i=1}^{a}\sum\limits_{j=1}^{b}f((i,j))$

先简化。

\begin{eqnarray*} \sum\limits_{i=1}^{a}\sum\limits_{j=1}^{b}f((i,j)) &=& \sum_{d=1}^{min(a,b)}\sum\limits_{i=1}^{a}\sum\limits_{j=1}^{b}f(d)[(i,j)=d] \newline &=& \sum_{d=1}^{min(a,b)}\sum\limits_{i=1}^{\lfloor \frac{a}{d} \rfloor}\sum\limits_{j=1}^{\lfloor \frac{a}{d} \rfloor}f(d)[(i,j)=1] \newline &=& \sum\limits_{{\rm{d = 1}}}^{\min (a,b)} {\sum\limits_{i = 1}^{\left\lfloor {\frac{a}{d}} \right\rfloor } {\sum\limits_{j = 1}^{\left\lfloor {\frac{b}{d}} \right\rfloor } {\sum\limits_{k|(i,j)}^{} {\mu (k)f(d)} } } } \newline  &=& \sum\limits_{d = 1}^{\min (a,b)} {\sum\limits_{k = 1}^{\min (\left\lfloor {\frac{a}{d}} \right\rfloor ,\left\lfloor {\frac{b}{d}} \right\rfloor )} {f(d)\mu (k)} \left\lfloor {\frac{a}{{kd}}} \right\rfloor \left\lfloor {\frac{b}{{kd}}} \right\rfloor }  \newline &=& \sum\limits_{T = kd = 1}^{\min (a,b)} {\sum\limits_{d|T}^{} {f(d)\mu (\frac{T}{d})} \left\lfloor {\frac{a}{T}} \right\rfloor \left\lfloor {\frac{b}{T}} \right\rfloor } \newline \end{eqnarray*}

所以只要能够预处理出$\sum\limits_{d|T} {f(d)\mu (\frac{T}{d})}$就能分块了。

注意观察该函数,根据$f()$取素因子次数的最大值及$\mu()$数论意义上的容斥性质,可以发现当$a_i$的值都一样时,才存在一个次数的组合使$\frac{T}{d}=p_1^{1}p_2^{1}…p_k^{1}$值无法被消去,因为它的$f()$值要比对称的组合$f(p_1^{0}p_2^{0}…p_k^{0})$大1,而其他的所有组合都可找到一个素因子数量对称的组合使得两者的$\mu$互为相反数而相消。

故最后$\sum\limits_{d|T} {f(d)\mu (\frac{T}{d})}=(-1)^{k+1}$

线性筛里处理数论函数。预处理其前缀和就好了。

 

/** @Date    : 2017-09-28 21:09:51
  * @FileName: bzoj 3309 反演.cpp
  * @Platform: Windows
  * @Author  : Lweleth (SoungEarlf@gmail.com)
  * @Link    : https://github.com/
  * @Version : $Id$
  */
#include <bits/stdc++.h>
#define LL long long
#define PII pair<int ,int>
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;

const int INF = 0x3f3f3f3f;
const int N = 1e6+20;
const double eps = 1e-8;


int c = 0;
bool vis[N*10];
int pri[N];

int cnt[N*10];
int k[N*10];
int f[N*10];

void prime()
{
	MMF(vis);
	for(int i = 2; i < 10000010; i++)
	{
		if(!vis[i])
		{
			pri[c++] = i;
			cnt[i] = 1;
			k[i] = i;//最小的素因子对应的幂
			f[i] = 1;
		}
		for(int j = 0; j < c && i * pri[j] < 10000010; j++)
		{
			vis[i * pri[j]] = 1;
			if(i % pri[j] == 0)//倍数
			{
				cnt[i * pri[j]] = cnt[i] + 1;//最小质因子次数+1
				k[i * pri[j]] = k[i] * pri[j];//幂增大1次
				int tmp = i / k[i];//除去该因子的幂
				if(tmp == 1)
					f[i * pri[j]] = 1;//说明只有一个因子
				else f[i * pri[j]] = (cnt[tmp]==cnt[i * pri[j]]?-f[tmp]:0);//判断次数是否相同
				break;
			}
			else
			{
				cnt[i * pri[j]] = 1;//首次出现默认次数为1
				k[i * pri[j]] = pri[j];//
				f[i * pri[j]] = (cnt[i]==1?-f[i]:0);
			}
			/*getchar();
			cout << i<<"~~"<<i * pri[j] << "~"<<k[i * pri[j]] <<endl;
			cout << cnt[i * pri[j]] << endl;*/
		}
	}
	for(int i = 1; i < 10000010; i++)
		f[i] += f[i - 1];
}
int main()
{
	int T;
	prime();
	cin >> T;
	while(T--)
	{
		LL a, b;
		scanf("%lld%lld", &a, &b);
		if(a > b)
			swap(a, b);
		LL ans = 0;
		for(int i = 1, last; i <= a; i = last + 1)
		{
			last = min(a/(a/i), b/(b/i));
			ans += (a / i) * (b / i) * (f[last] - f[i - 1]);
		}
		printf("%lld\n", ans);
	}
    return 0;
}
posted @ 2017-09-29 00:09  Lweleth  阅读(200)  评论(1编辑  收藏  举报