题解 P6280 【[USACO20OPEN]Exercise G】
首先这题和P4161几乎一模一样,(P4161要求k的个数,本题求所有k的和),所以双倍经验
然后我们来看这题,可以发现如果循环了几次可以回到原地,当且仅当形成了一个环,假如设每个环的长度是
我们设
接着发现这个东西可以滚动数组压缩一下,于是可以省掉一维
代码
#include <bits/stdc++.h>
#define ll long long//注意开long long
using namespace std;
const int N = 1e4 + 3;
bool vis[N]; vector<int> p;
ll f[N] = {1}, m;int n;
int main (){
p.push_back(0);//让素数的下标从一开始,使后面的转移更简洁
cin >> n >> m;
for (int i = 2; i <= n; i++){
if (!vis[i])p.push_back(i);
for (int j = i * i; j <= n; j += i)vis[j] = 1;
}//埃筛筛素数
for (int i = 1; i < p.size(); i++)
for (int j = n; j >= p[i]; j--){
int tmp = p[i];
while(tmp <= j)
f[j] = (f[j] + f[j - tmp] * tmp % m) % m, tmp *= p[i];
}
ll Ans = 0;
for (int i = 0; i <= n; i++)Ans = (Ans + f[i]) % m;
cout << Ans << endl;
return 0;
}