LG-P4270 [USACO18FEB]Cow Gymnasts P 题解
LG-P4270 [USACO18FEB]Cow Gymnasts P Solution
更好的阅读体验戳此进入
前面的几个性质的思路参考自 这篇Blog,主要是对一些我觉得难以理解的地方重写一下,以及对最后结论及实现进行更详细的证明。
题面
存在
对于样例,有
Solution
一道纯粹的人类智慧题。。。
然后我们这里定义的循环周期并不是一般圆周运动绕一圈的操作次数,而是一头原来在第
首先对于符合条件的排列,有好几个奇怪的性质:
- 对于第
层的奶牛,只能是从其他平台第 层的奶牛平移过来,而不可以是从更高层的奶牛掉下来。
证明:因为是符合条件的排列,我们假设序列中最高的层数为
- 对于第
层奶牛的循环周期(定义参考伊始)是 的约数。
证明:显然某一时刻第
- 第
层奶牛循环周期是第 层奶牛循环周期的约数。
证明:考虑由性质一,第
- 任意两个平台之间的奶牛数量差不超过
。
证明:由性质二不难得出
以此我们便可以得出结论:
证明:首先枚举层数最小的平台有
此时根据我们前面的性质一定有标号相同的点值相同,那么此时
然后此时我们还要考虑,为什么仅枚举是否为
随便举几个例子可以发现这个结论似乎正确,那么我们现在尝试严谨一点地去证明,有结论,对于所有非
首先考虑如果有非
所以换一个说法理解,我们枚举的便为此处是
然后发现数据范围这个柿子肯定过不去,于是考虑优化,继续推柿子:
这个式子应该是可以继续推下去直到严格
显然我们可以通过分解质因数求欧拉函数,具体地,令
那么:
然后我们答案式子枚举的是 long long
。然后过程中是需要先让 long long
,当然像我一样直接用 __int128_t
可以直接忽略这些问题。
至此此题解决,还是很精妙的。
Code
#define _USE_MATH_DEFINES
#include <bits/extc++.h>
#define PI M_PI
#define E M_E
#define npt nullptr
#define SON i->to
#define OPNEW void* operator new(size_t)
#define ROPNEW(arr) void* Edge::operator new(size_t){static Edge* P = arr; return P++;}
using namespace std;
using namespace __gnu_pbds;
mt19937 rnd(random_device{}());
int rndd(int l, int r){return rnd() % (r - l + 1) + l;}
bool rnddd(int x){return rndd(1, 100) <= x;}
typedef unsigned int uint;
typedef unsigned long long unll;
typedef long long ll;
typedef long double ld;
#define MOD (ll)(1e9 + 7)
template< typename T = int >
inline T read(void);
ll N;
int tot(0);
pair < ll, int > fact[1100000];
int cur[1100000];
__int128_t ans(0);
__int128_t qpow(ll a, ll b){
__int128_t ret(1), mul(a);
while(b){
if(b & 1)ret = ret * mul % MOD;
b >>= 1;
mul = mul * mul % MOD;
}return ret;
}
void dfs(int p = 1, ll base = 1, __int128_t phi = 1, __int128_t div = 1){
if(p > tot){
phi *= base, phi /= div, phi %= MOD;
ans = (ans + phi * qpow(2, N / base) % MOD) % MOD;
return;
}
dfs(p + 1, base, phi, div);
phi *= fact[p].first - 1;
div *= fact[p].first;
for(int i = 1; i <= fact[p].second; ++i)
base *= fact[p].first, dfs(p + 1, base, phi, div);
}
int main(){
N = read < ll >();
ll tmp(N); ll cur(2), cnt(0);
while(tmp > 1){
if(cur * cur > tmp)break;
while(tmp % cur == 0)tmp /= cur, ++cnt;
if(cnt)fact[++tot] = {cur, cnt}, cnt = 0;
++cur;
}if(tmp > 1)fact[++tot] = {tmp, 1};
dfs();
ans = ((((ans + 2 - N) % MOD) - qpow(2, N)) % MOD + MOD) % MOD;
printf("%lld\n", (ll)ans);
fprintf(stderr, "Time: %.6lf\n", (double)clock() / CLOCKS_PER_SEC);
return 0;
}
template < typename T >
inline T read(void){
T ret(0);
short flag(1);
char c = getchar();
while(c != '-' && !isdigit(c))c = getchar();
if(c == '-')flag = -1, c = getchar();
while(isdigit(c)){
ret *= 10;
ret += int(c - '0');
c = getchar();
}
ret *= flag;
return ret;
}
UPD
update-2022_11_09 初稿
本文作者:tsawke
本文链接:https://www.cnblogs.com/tsawke/p/16945625.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步