CF839 D 容斥

求$gcd>1$的所有$gcd(a_i,a_{i+1}…a_{n})*(n-i+1)$的和

首先先标记所有出现的数。从高到低枚举一个数k,记录它的倍数出现次数cnt,那么当前所有组合的答案就是$ans[k]=cnt*2^{cnt-1}$,但是这个答案只有gcd=k的组合是没被计算过的,其他已经被k的倍数计算过了,所以要减去此前算过的所有n的$ans[k|n]$。

 

/** @Date    : 2017-08-13 14:38:39
  * @FileName: 839D 容斥.cpp
  * @Platform: Windows
  * @Author  : Lweleth ([email protected])
  * @Link    : https://github.com/
  * @Version : $Id$
  */
#include 
#define LL long long
#define PII pair
#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;
const LL mod = 1e9 + 7;

LL fpow(LL x, LL n)
{
	LL ans = 1;
	while(n > 0)
	{
		if(n & 1)
			ans = (ans * x % mod + mod) % mod;
		x = (x * x % mod + mod)% mod;
		n >>= 1;
	}
	return ans;
}

LL cnt[N];
LL rep[N];
int n;
int main()
{
	while(cin >> n)
	{
		MMF(cnt);
		MMF(rep);
		int x;
		for(int i = 0; i < n; i++) scanf("%d", &x), cnt[x]++;

		LL ans = 0;
		for(int i = 1000000; i >= 2; i--)
		{
			LL c = 0;
			for(int j = i; j <= 1000000; j+=i)
				c += cnt[j];
			if(!c)
				continue;
			//cout << i << c << endl;
			rep[i] = (c * fpow(2, c - 1) % mod + mod) % mod;
			//cout << rep[i] << endl;
			for(int j = i + i; j <= 1000000; j+=i)
				if(rep[j]) 
					rep[i] = (rep[i] - rep[j] + mod) % mod;
			//cout << rep[i] << endl;
			ans = (ans + rep[i] * (LL)i % mod + mod) % mod;
		}
		printf("%lld\n", ans);
	}
    return 0;
}

转载于:https://www.cnblogs.com/Yumesenya/p/7449876.html

你可能感兴趣的:(CF839 D 容斥)