题解 P4270 【[USACO18FEB]Cow Gymnasts】
hhhhhhazard · · 题解
想要却不可得,你奈人生何
这题考场写炸.zip,瞎搞出答案???然后精度爆炸...参考了一下题解
预备知识: φ(x) = x\frac{(p1-1)(p2-1)...(pi-1)}{p1p2..pi}
题意: 给定
结论一:对于每个层数的奶牛,只能从其他平台相同层数的奶牛平移过来,不能从层数较高的奶牛落下得到。
证明: 假设平台中层数最高为
结论二:第i层的奶牛的循环周期是i的约数
证明: 依题意,每层的奶牛都是循环的,对于某个平台层数为
结论三:第i-1 层的奶牛的循环周期是第i 层奶牛循环周期的约数
证明: 对于一个平台第滑稽
结论四:任意两个平台上的奶牛数量之差不超过一
证明: 对于两个相邻层的奶牛,周期分别为
结论五: ans = 2-n + \sum_{m=1}^{n-1}\ 2^{gcd(m,n)}
证明:这里的
优化
我们可以观察一下科学养锁,我们假设一下gcd(n, m) = n/g ,我们的洗个马就可以化简成wjh的搜索天下第一就可以卡过去了,然后精度方面,在最后的答案因为n是有可能比我们的模数大的,所以我们要
ans = (ans + 2 - N) % mod;
if (ans < 0)
ans += mod;
而不是
ans = (ans + 2 - N + mod) % mod;
然后你就考崩了...下面是代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll mod = 1e9 + 7;
ll ans, N, n;
vector <ll> q;
vector <int> cnt;
inline ll ksm(ll a, ll p) {
ll rt = 1;
while (p) {
if (p&1)
rt = rt * a % mod;
a = a * a % mod;
p>>=1;
}
return rt;
}
void dfs(int num, ll g, ll m1, ll m2) {
if (num == q.size()) {
if (g == 1)
return;
ans+=ksm(2,N/g)*(g/m2%mod*m1%mod)%mod;
ans%=mod;
return;
}
dfs(num+1, g, m1, m2);
m1 = m1 * (q[num] - 1) % mod;
m2 = m2 * q[num];
for (int i = 1; i <= cnt[num]; i++) {
g = g * q[num];
dfs(num+1, g, m1, m2);
}
}
int main() {
cin >> N;
n = N;
for (ll i = 2; i * i <= n; i++)
if (n % i == 0) {
int tot = 0;
q.push_back(i);
while (n % i==0) {
n /= i;
tot++;
}
cnt.push_back(tot);
}
if (n > 1) {
q.push_back(n);
cnt.push_back(1);
}
dfs(0, 1, 1, 1);
ans = (ans + 2 - N) % mod;
if (ans < 0)
ans += mod;
cout << ans;
return 0;
}