一场给dalao们吐槽到不行。全场B题最后终测挂了9/10的div2。
hack频频出错。B题比D题还难的场。。
多校中插一脚cf。hhhhhhh题意:
给一个序列,要求找一个可以不连续长度为k的子序列满足下标 i1<i2<i3<...<ik
有满足 p=gcd(ai1,ai2..aik),p>1 可以贡献p * k的价值。
现在问对于这个序列的所有情况的贡献是多少。思路:
其实可以不要被这个下标蒙蔽了。下标没什么的。只是限定你只能使用一次这个序列而已。
比赛的时候发现其实对于每一个位置答案就是 i∗∑i∗Cin ,这里的n为这个数与这个数的倍数的总和。
然后答案可能有重复容斥一下就好了(本人容斥比较弱。就写过两次。估计如果比赛真要写容斥,脑子抽的话容斥怎么写都不对)
然后发现 i∗Cin 这个东西怎么那么难算啊。算不出啊。是不是思路错了。。然后就挂机一个钟了
其实dalao都说。不难发现。 Cin=Ci−1n−1∗n/i
所以 i∗Cin=n∗Ci−1n−1
然后 ∑Ci−1n−1明显等于2n−1
所以最后转换成 n∗2n−1 即可
代码如下:
/*
@resources: codeforces 839d
@date: 2017-08-13
@author: QuanQqqqq
@algorithm: 容斥
*/
#include <bits/stdc++.h>
#define ll long long
#define MAXN 2000005
#define MOD 1000000007
using namespace std;
ll tot[MAXN], mark[MAXN];
ll c[MAXN];
ll ksm(ll a, ll n) {
ll ans = 1, t = a;
while (n) {
if (n & 1) {
ans = (t * ans) % MOD;
}
t = (t * t) % MOD;
n >>= 1;
}
return ans;
}
int main() {
ll n, maxt = 0, tmp;
scanf("%lld", &n);
for (ll i = 0; i < n; i++) {
scanf("%lld", &tmp);
tot[tmp]++;
maxt = max(maxt, tmp);
}
for (ll i = 2; i <= maxt; i++) {
ll sum = 0;
for (ll j = i; j <= maxt; j += i) {
sum += tot[j];
}
if (sum == 0) {
continue;
}
if (mark[sum] != 0) {
c[i] = mark[sum];
continue;
}
c[i] = (sum * ksm(2, sum - 1)) % MOD;
mark[sum] = c[i];
}
ll ans = 0;
for (ll i = maxt; i >= 2; i--) {
for (ll j = i * 2; j <= maxt; j += i) {
c[i] -= c[j];
c[i] = (c[i] % MOD + MOD) % MOD;
}
ans += (c[i] * i) % MOD;
ans %= MOD;
}
printf("%lld\n", ans);
}