前面的几个性质的思路参考自 这篇Blog,主要是对一些我觉得难以理解的地方重写一下,以及对最后结论及实现进行更详细的证明。
存在
对于样例,有
一道纯粹的人类智慧题。。。
然后我们这里定义的循环周期并不是一般圆周运动绕一圈的操作次数,而是一头原来在第
首先对于符合条件的排列,有好几个奇怪的性质:
证明:因为是符合条件的排列,我们假设序列中最高的层数为
证明:显然某一时刻第
证明:考虑由性质一,第
证明:由性质二不难得出
以此我们便可以得出结论:
证明:首先枚举层数最小的平台有

此时根据我们前面的性质一定有标号相同的点值相同,那么此时
然后此时我们还要考虑,为什么仅枚举是否为
随便举几个例子可以发现这个结论似乎正确,那么我们现在尝试严谨一点地去证明,有结论,对于所有非
首先考虑如果有非
所以换一个说法理解,我们枚举的便为此处是
然后发现数据范围这个柿子肯定过不去,于是考虑优化,继续推柿子:
这个式子应该是可以继续推下去直到严格
显然我们可以通过分解质因数求欧拉函数,具体地,令
那么:
然后我们答案式子枚举的是 long long。然后过程中是需要先让 long long,当然像我一样直接用 __int128_t 可以直接忽略这些问题。
至此此题解决,还是很精妙的。
86123
45678910
11using namespace std;12using namespace __gnu_pbds;13
14mt19937 rnd(random_device{}());15int rndd(int l, int r){return rnd() % (r - l + 1) + l;}16bool rnddd(int x){return rndd(1, 100) <= x;}17
18typedef unsigned int uint;19typedef unsigned long long unll;20typedef long long ll;21typedef long double ld;22
2324
25template< typename T = int >26inline T read(void);27
28ll N;29int tot(0);30pair < ll, int > fact[1100000];31int cur[1100000];32__int128_t ans(0);33
34__int128_t qpow(ll a, ll b){35 __int128_t ret(1), mul(a);36 while(b){37 if(b & 1)ret = ret * mul % MOD;38 b >>= 1;39 mul = mul * mul % MOD;40 }return ret;41}42
43void dfs(int p = 1, ll base = 1, __int128_t phi = 1, __int128_t div = 1){44 if(p > tot){45 phi *= base, phi /= div, phi %= MOD;46 ans = (ans + phi * qpow(2, N / base) % MOD) % MOD;47 return;48 }49 dfs(p + 1, base, phi, div);50 phi *= fact[p].first - 1;51 div *= fact[p].first;52 for(int i = 1; i <= fact[p].second; ++i)53 base *= fact[p].first, dfs(p + 1, base, phi, div);54}55
56int main(){57 N = read < ll >();58 ll tmp(N); ll cur(2), cnt(0);59 while(tmp > 1){60 if(cur * cur > tmp)break;61 while(tmp % cur == 0)tmp /= cur, ++cnt;62 if(cnt)fact[++tot] = {cur, cnt}, cnt = 0;63 ++cur;64 }if(tmp > 1)fact[++tot] = {tmp, 1};65 dfs();66 ans = ((((ans + 2 - N) % MOD) - qpow(2, N)) % MOD + MOD) % MOD;67 printf("%lld\n", (ll)ans);68 fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);69 return 0;70}71
72template < typename T >73inline T read(void){74 T ret(0);75 short flag(1);76 char c = getchar();77 while(c != '-' && !isdigit(c))c = getchar();78 if(c == '-')flag = -1, c = getchar();79 while(isdigit(c)){80 ret *= 10;81 ret += int(c - '0');82 c = getchar();83 }84 ret *= flag;85 return ret;86}update-2022_11_09 初稿