E - Sum of gcd of Tuples (Hard)
题意:
有 n 个大小为 1∼k 的数,找出n个数的所有排列中的 gcd(a1,a2,...,an) 之和。
数据范围:
2 ≤ N ≤
1 ≤ K ≤
思路:
设 dp[i] = gcd(a1,a2,a3,……,an) = i 时的排列数量,所以排列中的 ai 必须是 i 的倍数,有 (向下取整)个数,在 n 个位置随意选择。总共有种。
但是,这里面的排列不全是 gcd= i 的,还包含 gcd = i*2, gcd = i*3……的,所以要减去这些不符合的。如:i = 2,gcd[2] 中还包含 gcd[4], gcd[6]……。
实现:倒序枚举 i (k~1),先用快速幂求出;再枚举 i 的倍数 j ,减去 dp[j]。
Code:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<vector>
#include<queue>
using namespace std;
#define x first
#define y second
#define int long long
const int N = 200010, INF = 0x3f3f3f3f, mod = 1e9 + 7;
typedef pair<int, int>PII;
int n, k;
int dp[N]; //dp[i]表示gcd=i的排列个数
//快速幂
int qmi(int a, int k)
{
int res = 1;
while (k)
{
if (k & 1)
res = (res * a) % mod;
k >>= 1;
a = a * a % mod;
}
return res;
}
void solve()
{
cin >> n >> k;
int ans = 0;
for (int i = k; i >= 1; i--) //倒序枚举i
{
int num = k / i; //num为小于k的i的倍数的个数
dp[i] = qmi(num, n);
for (int j = i + i; j <= k; j += i) //枚举i的倍数j
dp[i] = (dp[i] - dp[j] + mod) % mod; //减去gcd[j],这里加mod是为了防止值为负数,因为算qmi时已经取modl了
ans = (ans + dp[i] * i) % mod; //计算i*gcd[i]的总和
}
cout << ans << endl;
}
signed main()
{
int t = 1;
//cin >> t;
while (t--)
{
solve();
}
return 0;
}
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
吐槽:本题注意点:
注意模mod时,为了避免负数注意多加一次mod。