【裴蜀定理】【CF1091C】 New Year and the Sphere Transmission

Description

n 个人围成一个圈,按照顺时针从 1n 编号。第 1 个人会拿到一个球,他指定一个数字 k,然后会将球传给他后面顺指针数第 k 个人。再次传到 1 后游戏结束。定义一次游戏的 ans 为所有拿到球的人的编号之和 (1 只算一次)。求所有可能的 ans,按照升序输出,保证不超过 105

Input

一个整数 n

Output

一行多个整数,代表所有可能的 ans。按照是升序输出。

Hint

1  n  109

Solution

我们不妨将位置从 0  n1 编号。则一个位置 p 会在一次传球中被传到当且仅当 p  xk (modn),其中 x  Z+

考虑上面的同余方程,他等价于 xk + yn = p,其中 x,y  Z+。根据裴蜀定理,这个方程有整数解当且仅当 gcd(k,n)p。考虑因为 k  [1,n],所以 gcd(k,n) 显然与 n 的因数一一对应。于是直接枚举 n 的因数 s,则对答案产生贡献的只有 0,s,2s,3s  ts,其中 t = ns。这是一个等差数列,直接使用等差数列求和公式可以 O(1) 计算答案。考虑我们位置是从 0  n1 编号的,所以每个位置的贡献都少算了 1,总共少算了 t,最后加上 t 即可。另外因为编号最大的位置 ts 事实上就是 0 号位置,我们对这个位置的贡献算了两遍,减掉第二遍计算的贡献 n 即可。

Code

#include <cmath>
#include <cstdio>
#include <set>
#ifdef ONLINE_JUDGE
#define freopen(a, b, c)
#endif
#define rg register
#define ci const int
#define cl const long long

typedef long long int ll;

namespace IPT {
	const int L = 1000000;
	char buf[L], *front=buf, *end=buf;
	char GetChar() {
		if (front == end) {
			end = buf + fread(front = buf, 1, L, stdin);
			if (front == end) return -1;
		}
		return *(front++);
	}
}

template <typename T>
inline void qr(T &x) {
	rg char ch = IPT::GetChar(), lst = ' ';
	while ((ch > '9') || (ch < '0')) lst = ch, ch=IPT::GetChar();
	while ((ch >= '0') && (ch <= '9')) x = (x << 1) + (x << 3) + (ch ^ 48), ch = IPT::GetChar();
	if (lst == '-') x = -x;
}

template <typename T>
inline void ReadDb(T &x) {
	rg char ch = IPT::GetChar(), lst = ' ';
	while ((ch > '9') || (ch < '0')) lst = ch, ch = IPT::GetChar();
	while ((ch >= '0') && (ch <= '9')) x = x * 10 + (ch ^ 48), ch = IPT::GetChar();
	if (ch == '.') {
		ch = IPT::GetChar();
		double base = 1;
		while ((ch >= '0') && (ch <= '9')) x += (ch ^ 48) * ((base *= 0.1)), ch = IPT::GetChar();
	}
	if (lst == '-') x = -x;
}

namespace OPT {
	char buf[120];
}

template <typename T>
inline void qw(T x, const char aft, const bool pt) {
	if (x < 0) {x = -x, putchar('-');}
	rg int top=0;
	do {OPT::buf[++top] = x % 10 + '0';} while (x /= 10);
	while (top) putchar(OPT::buf[top--]);
	if (pt) putchar(aft);
}

ll n;
std::set<ll>ss;

void work(cl);

int main() {
	freopen("1.in", "r", stdin);
	qr(n);
	for (rg int i = 1, sn = sqrt(n); i <= sn; ++i) if (!(n % i)) {
		work(i);
		work(n / i);
	}
	for (std::set<ll>::iterator it = ss.begin(); it != ss.end(); ++it) qw(*it, ' ', true);
	putchar('\n');
	return 0;
}

void work(cl s) {
	ll y = n / s;
	ll ans = (((s + y * s) * y) >> 1) + y - n;
	ss.insert(ans);
}
posted @   一扶苏一  阅读(314)  评论(0编辑  收藏  举报
编辑推荐:
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示