[USACO18FEB]Cow Gymnasts

题目

传送门 to luogu

传送门 to BZOJ

题目描述
Bored of farm life, the cows have sold all their earthly possessions and joined the crew of a traveling circus. So far, the cows had been given easy acts: juggling torches, walking tightropes, riding unicycles – nothing a handy-hoofed cow couldn’t handle. However, the ringmaster wants to create a much more dramatic act for their next show. The stage layout for the new act involves N N N platforms arranged in a circle. On each platform, between 1 1 1 and N N N cows must form a stack, cow upon cow upon cow. When the ringmaster gives the signal, all stacks must simultaneously fall clockwise, so that the bottom cow in a stack doesn’t move, the cow above her moves one platform clockwise, the next cow moves two platforms clockwise, and so forth. Being accomplished gymnasts, the cows know they will have no trouble with the technical aspect of this act. The various stacks of cows will not “interfere” with each other as they fall, so every cow will land on the intended platform. All of the cows landing on a platform form a new stack, which does not fall over.

The ringmaster thinks the act will be particularly dramatic if after the stacks fall, the new stack on each platform contains the same number of cows as the original stack on that platform. We call a configuration of stack sizes “magical” if it satisfies this condition. Please help the cows by computing the number of magical configurations. Since this number may be very large, compute its remainder modulo 1 0 9 + 7 10^9+7 109+7.

Two configurations are considered distinct if there is any platform for which the configurations assign a different number of cows.

n n n 个台子,摆成一圈。第 i i i 个台子上垒了 a i ( 1 ≤ a i ≤ n ) a_i(1\le a_i\le n) ai(1ain) 头奶牛。妹儿一声令下,所有奶牛都会往顺时针方向倒下。

具体地,最底下的奶牛还会在原来的台子上,它上面的奶牛会落在顺时针数第一个台子上,更上面的一个落在顺时针数第二个台子上,以此类推。

形式化地,用 f ( x ) f(x) f(x) 表示新的 a x a_x ax ,令 a x ( − n < x ≤ 0 ) = a x + n a_x(-n<x\le 0)=a_{x+n} ax(n<x0)=ax+n ,有 f ( x ) = ∑ i = 0 n − 1 [ a x − i > i ] f(x)=\sum_{i=0}^{n-1}[a_{x-i}>i] f(x)=i=0n1[axi>i]

现在告诉你 n n n ,求有多少个不同的 a a a 数组,使得妹儿一声令下后,新的 a a a 数组与原来相同。即: ∀ x ∈ [ 1 , n ] , f ( x ) = a x \forall x\in [1,n],f(x)=a_x x[1,n],f(x)=ax 。答案取模 1 0 9 + 7 10^9+7 109+7 后输出(千万别忘了, 1 ≤ a x ≤ n 1\le a_x\le n 1axn )。

输入格式
The input is a single integer N ( 1 ≤ N ≤ 1 0 12 ) N(1\le N\le10^{12}) N(1N1012)

一行一个不超过 1 0 12 10^{12} 1012 的正整数 n n n ,含义如题。

输出格式
A single integer giving the number of magical configurations modulo 1 0 9 + 7 10^9+7 109+7.

一行一个正整数,表示答案除以 ( 1 0 9 + 7 ) (10^9+7) (109+7) 的结果。

思路

从一堆奶牛的角度来看,是往旁边倒下;从一层的奶牛来看,是每一个都往顺时针方向移动相同的个数。譬如最下面的奶牛,是不会移动的;从下往上数的第二层的所有奶牛,都会掉到下一个台子上,相当于是顺时针旋转了 1 1 1 步。

我们将最下面一层的层数编号为 0 0 0 ,往上逐层增加 1 1 1 ,发现 i i i 层的奶牛每个要移动 i i i 个单位

结论一:每一层都是自给自足的

假设最高(奶牛最多)的一个台子上有 M M M 个奶牛(也就是有 M − 1 M-1 M1 层)。那么计算一下:它逆时针方向的 M − 1 M-1 M1 个台子都要“给”它一只奶牛——逆时针方向的第 M M M 个台子如果要给它一只奶牛的话,就需要移动 M M M 个单位(也就是有 M M M 层),比最高的 M − 1 M-1 M1 层还要高,不可能。而前面的第 i i i ( 0 < i < M ) (0<i<M) (0<i<M) 台子的奶牛中,移动到该台子的奶牛恰好处于第 i i i 层——也就是每一层都与前面的一个台子对应。所以最高的台子恰好是由前面的几个奶牛同层平移得到的。

即使有多个最高的,也是一样的。给一张图吧!——最右边的是最高的。

在这里插入图片描述

完了吗?没有!这只是最高的台子的情况。接下来,就可以用“归纳法”:最高的那一层,必定是同层平移,所以没有掉下去的。如果掉下去了,最上面一层的奶牛总数就会减少,不可能。故:最上面一层对下面的每一层都没有影响。然后你就可以去掉最高的那一层。不断如此,你就可以得到结论一。

有了结论一后,下面的叙述都只针对某一层,设为第 i i i 层。由于是循环的,所以将台子从 0 0 0 开始编号。

结论二:如果第 x x x 个台子上有奶牛,那么第 ( x + k i )   m o d   n (x+ki)\bmod n (x+ki)modn 个台子上有奶牛

显然。因为移动步数是 i i i 。当然,这种环上一直加 i i i 就会出现 循环节 T i T_i Ti

可以给一个比较通用的结论:在长度为 n n n 的环上,每次走 i i i 步,得到的循环节 T i T_i Ti 满足 T i ∣ i , T i ∣ n T_i|i,T_i|n Tii,Tin ,并且 T i T_i Ti 尽可能的大。为什么我不直说 T i = gcd ⁡ ( i , n ) T_i=\gcd(i,n) Ti=gcd(i,n) 呢?很快你会知道。

结论三:除了最上面一层,其他都是满的

考虑相邻的两层, i ( i ≠ 0 ) i(i\ne 0) i(i=0) i + 1 i+1 i+1 (设 i + 1 i+1 i+1 层有奶牛存在)。

如果第 x x x 个台子上存在第 i + 1 i+1 i+1 层的奶牛,那么 x + i + 1 x+i+1 x+i+1 的台子上有第 i + 1 i+1 i+1 层的奶牛。显然奶牛不能悬空,所以 x + i + 1 x+i+1 x+i+1 上必须有第 i i i 层的奶牛。然后 x + 2 ( i + 1 ) x+2(i+1) x+2(i+1) 上有奶牛, x + 3 ( i + 1 ) x+3(i+1) x+3(i+1)有奶牛,以此类推。我们惊奇地发现, i + 1 i+1 i+1 作为步长,也可以给第 i i i 层带来周期!

根据我们在结论二中的经验, T i ∣ i T_i|i Tii T i ∣ i + 1 T_i|i+1 Tii+1 T i ∣ n T_i|n Tin

注意到 gcd ⁡ ( i , i + 1 ) = 1 \gcd(i,i+1)=1 gcd(i,i+1)=1 ,二者互质!很显然,这样一来,唯一满足条件的 T i T_i Ti 就是一。

也就是说, T i = 1 T_i=1 Ti=1

所以除了最上面一层,其他的层都是满的。一步一步的走都填不满?

结论四: a n s = 2 − n + ∑ m = 1 n − 1 2 gcd ⁡ ( n , m ) ans=2-n+\sum_{m=1}^{n-1}2^{\gcd(n,m)} ans=2n+m=1n12gcd(n,m)

m m m 就是在枚举最矮的台子有 m m m 只奶牛(也就是 m − 1 m-1 m1 层)。事实上,最多也只有 m m m 层的台子了,否则第 m m m 层就会被填满,最少的台子上也该有 m + 1 m+1 m+1 只奶牛。

考虑更高的一层:根据结论二,循环节是 gcd ⁡ ( n , m ) \gcd(n,m) gcd(n,m)。那么,我们就有 gcd ⁡ ( n , m ) \gcd(n,m) gcd(n,m) 个不同的组。每一组之内的台子的“状态”(是否有 m m m 层)相同。如图。
如图
比如红颜色的是一组,两个最近的红颜色台子距离为 gcd ⁡ ( n , m ) \gcd(n,m) gcd(n,m)

gcd ⁡ ( n , m ) \gcd(n,m) gcd(n,m) 个组,不能每一个都选——否则就不存在只有 m m m 只奶牛的台子,而这是我们枚举的最矮的台子——方案数就是 2 gcd ⁡ ( n , m ) − 1 2^{\gcd(n,m)}-1 2gcd(n,m)1 呗。

发现我们没有考虑最矮的台子上有 n n n 只奶牛的情况。这不就只有一种情况,全部都是 n n n 吗?

总结一下: a n s = 1 + ∑ m = 1 n − 1 ( 2 gcd ⁡ ( n , m ) − 1 ) ans=1+\sum_{m=1}^{n-1}(2^{\gcd(n,m)}-1) ans=1+m=1n1(2gcd(n,m)1)

把循环中的 − 1 -1 1 提出即可得到等价的式子

a n s = 2 − n + ∑ m = 1 n − 1 2 gcd ⁡ ( n , m ) ans=2-n+\sum_{m=1}^{n-1}2^{\gcd(n,m)} ans=2n+m=1n12gcd(n,m)

代码实现加速

目前时间复杂度是 O ( n log ⁡ n ) \mathcal O(n\log n) O(nlogn) 。很快,但还不够快: n = 1 0 12 n=10^{12} n=1012 怎么办?

基操: gcd ⁡ \gcd gcd 的数量是 2 n 2\sqrt{n} 2n ,枚举它,杠杠的!

gcd ⁡ ( n , m ) = n g ( g ≠ 1 ) \gcd(n,m)=\frac{n}{g}(g\ne 1) gcd(n,m)=gn(g=1) ,那么在 [ 1 , n ) [1,n) [1,n) 中不同的 m m m 的数量显然是 φ ( g ) \varphi(g) φ(g)

a n s = 2 − n + ∑ g ∣ n 2 n g φ ( g ) ans=2-n+\sum_{g|n}2^{\frac{n}{g}}\varphi(g) ans=2n+gn2gnφ(g)

那么 φ ( g ) \varphi(g) φ(g) 的计算就得用

φ ( x ) = x ∏ i = 1 k p i − 1 p i \varphi(x)=x\prod_{i=1}^{k}\frac{p_i-1}{p_i} φ(x)=xi=1kpipi1

我们可以用 d f s dfs dfs 枚举质因子的指数来枚举 g g g ,所以就可以顺便算出这个长长的 φ \varphi φ

至于其他方法,作者就不介绍了。其实是不会

代码

#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;

const int MAXN = 1000000, MOD = 1000000007;

inline int qkpow(long long base,int q){
	long long ans = 1; base %= MOD;
	while(q){
		if(q&1) ans = (ans*base)%MOD;
		q >>= 1, base = (base*base)%MOD;
	}
	return ans;
}

vector<pair<long long,int> > ys; int ys_len;
void Divide(long long n){ // 质因数分解
	for(int i=2; 1ll*i*i<=n; ++i){
		int cnt = 0;
		while(n == n/i*i)
			n /= i, ++ cnt;
		if(cnt) ys.push_back(make_pair(i,cnt));
	}
	if(n != 1) ys.push_back(make_pair(n,1));
	ys_len = ys.size();
}

long long n, ans = 0;
void dfs(int t,long long g,long long up,long long down){
// t表示思考到了p_t
	if(t == ys_len){
		if(g == 1) return ; // g != 1 是前提哦
		ans=(g/down*up%MOD*qkpow(2,(n/g)%(MOD-1))%MOD+ans)%MOD;
		return ;
	}
	dfs(t+1,g,up,down); // g不含约数p_t
	up=up*(ys[t].first-1)%MOD, down*=ys[t].first;
	// 否则重新计算phi
	for(int i=1; i<=ys[t].second; ++i){
		g *= ys[t].first;
		dfs(t+1,g,up,down);
	}
}

int main()
{
	cin >> n;
	Divide(n);
	dfs(0,1,1,1);
	ans = ((ans+1-(n-1))%MOD+MOD)%MOD;
	cout << ans;
	return 0;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Go语言(也称为Golang)是由Google开发的一种静态强类型、编译型的编程语言。它旨在成为一门简单、高效、安全和并发的编程语言,特别适用于构建高性能的服务器和分布式系统。以下是Go语言的一些主要特点和优势: 简洁性:Go语言的语法简单直观,易于学习和使用。它避免了复杂的语法特性,如继承、重载等,转而采用组合和接口来实现代码的复用和扩展。 高性能:Go语言具有出色的性能,可以媲美C和C++。它使用静态类型系统和编译型语言的优势,能够生成高效的机器码。 并发性:Go语言内置了对并发的支持,通过轻量级的goroutine和channel机制,可以轻松实现并发编程。这使得Go语言在构建高性能的服务器和分布式系统时具有天然的优势。 安全性:Go语言具有强大的类型系统和内存管理机制,能够减少运行时错误和内存泄漏等问题。它还支持编译时检查,可以在编译阶段就发现潜在的问题。 标准库:Go语言的标准库非常丰富,包含了大量的实用功能和工具,如网络编程、文件操作、加密解密等。这使得开发者可以更加专注于业务逻辑的实现,而无需花费太多时间在底层功能的实现上。 跨平台:Go语言支持多种操作系统和平台,包括Windows、Linux、macOS等。它使用统一的构建系统(如Go Modules),可以轻松地跨平台编译和运行代码。 开源和社区支持:Go语言是开源的,具有庞大的社区支持和丰富的资源。开发者可以通过社区获取帮助、分享经验和学习资料。 总之,Go语言是一种简单、高效、安全、并发的编程语言,特别适用于构建高性能的服务器和分布式系统。如果你正在寻找一种易于学习和使用的编程语言,并且需要处理大量的并发请求和数据,那么Go语言可能是一个不错的选择。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值