CF839D Winter is here 题解

题面在这!

思路

对于这个数组的每个区间分别做\(\gcd\),然后再求贡献,这样显然不行...怎么办?我们就从\(\gcd\)入手,我们枚举\(\gcd\),然后求助每个可行的\(\gcd\)在这个数组中的贡献是多少。

现在我们设置几个数组:

\(cnt_i\)表示在原来的数组中\(i\)出现的次数,\(dp_i\)表示所有\(\gcd\)\(i\)的区间的总长度(由乘法分配律可知,每个区间的长度合并之后对于整体贡献的影响不会改变)

如果说当前我们求出了\(i\)的倍数的个数\(res\),那么它的\(dp\)值就是:

\(\sum\limits_{i=1}^{res}\tbinom{res}{i}\times i\)

=\(\sum\limits_{i=1}^{res}\frac{res!\times i}{i!(res-i)!}\)

=\(res\times \sum\limits_{i=1}^{res}\frac{(res-1)!}{(i-1)!(res-i)!}\)

=\(res\times \sum\limits_{i=0}^{res-1}\tbinom{res-1}{i}\)

由二项式定理(或者组合数的意义)可以得到:

=\(res*2^{res-1}\)

我们就可以愉快的求解了!

\(ACcode\)

#include<bits/stdc++.h>
#define F(i,l,r) for(register int i=l;i<=r;i++)
#define D(i,r,l) for(register int i=r;i>=l;i--)
#define ll long long
#define mem(a,b) memset(a,b,sizeof(a))
#define p_b push_back
#define m_p make_pair
#define il inline
const int INF=0x3f3f3f3f,mod=1e9+7,N=1e6+5;
using namespace std;
int cnt[N],fac[N]={1},n;
int ans,dp[N],a[N],maxn;
int main() {
	scanf("%d",&n);
	F(i,1,n) fac[i]=fac[i-1]*2ll%mod;//预处理出2^i
	F(i,1,n) {
		scanf("%d",&a[i]);
		maxn=max(maxn,a[i]);//求出枚举i(gcd)的范围
		cnt[a[i]]++;
	}
	D(i,maxn,2) {
		int res=0;
		F(j,i,maxn) res+=cnt[j],j+=i-1;//res意义如上文。这里j其实就是+=i了,奇怪的写法不要在意
		if(res) {
			dp[i]=fac[res-1]*1ll*res%mod;//公式
			F(j,2*i,maxn) dp[i]=(dp[i]+mod-dp[j])%mod,j+=i-1;//这里就是说把多出来的贡献减掉,因为我们只要i的贡献就好了i的倍数的都不要。记住+mod防止负数!
			ans=(ans+dp[i]*1ll*i%mod)%mod;//求出贡献
		}
	}
	printf("%d\n",ans);//输出
	return 0;
}
posted @ 2020-10-06 22:58  moonlateQZ  阅读(112)  评论(0)    收藏  举报