1. 程式人生 > >HDU 6134 && 2017 多校訓練:Battlestation Operational(莫比烏斯反演+積性函式)

HDU 6134 && 2017 多校訓練:Battlestation Operational(莫比烏斯反演+積性函式)

實在太長了直接放題目連結

這題就是求


考慮當Gcd(i, j)==1時,除了j為1的情況,其它時候i/j一定是小數,所以i/j向上取整相當於向下取整的結果+1

那麼有:(其中φ(i)為小於i與i互質的對數,即尤拉函式)


尤拉函式因為是積性函式,可以線性求出,令


為什麼上面等式成立?

對於所有的n/i,當n和i不互質時,很顯然它們除掉它們的Gcd之後就互質了,而等式左邊正是在列舉n的約數


那麼有:


其中莫比烏斯函式和原公式中的尤拉函式都可以O(n)預處理

這樣只要列舉後半部分就可以得出答案了

但很可惜這樣複雜度仍然是O(nsqrt(n))的所以比賽中就超時了。。。

卡了好久好久好久。。。

繼續想:

上面公式還可以轉


其中τ(n)表示n的約數個數,是積性函式也可以線性求出

那麼答案有


其中先預處理τ(n)的字首和,再預處理u(i)與t(n)字首和積的字首和

最後帶上尤拉函式再算一波字首和即可

直接O(1)查詢,程式碼很短,就是做了2個半小時。。。

#include<stdio.h>
#include<string.h>
#define mod 1000000007
#define LL long long
LL cnt[1000005], sum[1000005] = {0,1}, ans[1000005] = {0,1};
int main(void)
{
	LL n, i, j;
	for(i=1;i<=1000000;i++)
	{
		for(j=i;j<=1000000;j+=i)
			cnt[j]++;
	}
	for(i=2;i<=1000000;i++)
		sum[i] = (sum[i-1]+cnt[i-1]+1)%mod;
	for(i=1;i<=1000000;i++)
	{
		for(j=i+i;j<=1000000;j+=i)
			sum[j] = ((sum[j]-sum[i])%mod+mod)%mod;
	}
	for(i=2;i<=1000000;i++)
		ans[i] = (sum[i]+ans[i-1])%mod;
	while(scanf("%lld", &n)!=EOF)
		printf("%lld\n", ans[n]);
	return 0;
}