Luogu P4270 [USACO18FEB]Cow Gymnasts (打表找规律)
题意
题解
首先我们不竖着看奶牛而是横着看。从下往上把奶牛叫做处于第层。那么相当于第层的不动,第层的平移一格,第层的平移格,以此类推,第层平移格。假设每一层的最小正周期为,则显然有且。因为第层动了步恰好复原,就一定是最小正周期的倍数;因为是的环排列,所以最小正周期是的因数。
那么就有,又因为与互质,则与互质,所以与互质。
又因为为了不让第层的奶牛悬空,有第层的位置移动后必有第层的奶牛支撑,结合互质得到,在存在的情况下,。
意思就是说除了最上面一层,下面其它层周期均为,也就是全都占满了,每一层都是头奶牛。那么这个序列最多只能出现两个值,和。
我们枚举,最大周期是,答案就是
前面的表示最高层是第层,后面的表示在这一最大周期内每个值只有和两种取法,所以是的次幂,不是最大周期的情况也能包括在内。后面的表示不能全是,否则最高层就不是了。
暴力做是的,要考虑优化。
将相等的一起处理,对于,的的数量为,显然。所以答案就是
那么搜索出所有的因数,搜索过程中可以算出,最后时间复杂度为。是快速幂。
CODE
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
const int mod = 1000000007;
LL p[20], k[20], ans, a[20][40], n;
//p[i]表示第i个质因数,k[i]表示p[i]的幂
//a[i][j] = p[i]^j
int cnt;
inline LL qpow(LL a, LL b) {
LL re=1;
for(;b;b>>=1,a=a*a%mod)if(b&1)re=re*a%mod;
return re;
}
void dfs(int i, LL x, LL phi) {
if(i > cnt) {
if(x < n)
ans = (ans + 1ll * qpow(2, x) * phi % mod) % mod;
return;
}
for(int j = 0; j <= k[i]; ++j)
dfs(i+1, x*a[i][j], phi/a[i][j]/(j<k[i]?p[i]:1)*(j<k[i]?p[i]-1:1)); //计算phi(n/x)
}
int main () {
scanf("%lld", &n); LL N = n;
for(LL i = 2; i*i <= n; ++i)
if(n % i == 0) {
p[++cnt] = i;
a[cnt][0] = 1;
while(n % i == 0) {
n /= i, ++k[cnt];
a[cnt][k[cnt]] = a[cnt][k[cnt]-1] * i;
}
}
if(n > 1) p[++cnt] = n, k[cnt] = 1, a[cnt][0] = 1, a[cnt][1] = n;
n = N;
dfs(1, 1, n);
printf("%lld\n", ((ans - n + 2) % mod + mod) % mod); //记得加mod
}
事实上官方题解是这样子的 Here