[ABC290D] Marking

题意简述

接受三个参数 N,D,K。其中 N 表示有 N 个点,标号为 0,1,,(N1)

第一步,将点 0 标记,并且记录一个数 A,此时 A=0

此后,你要进行如下操作:

  1. (A+D)modNA
  2. 如果点 A 已经被标记,(A+1)modNA。、
  3. 标记点 A

显然最多进行 N 次操作。求问第 K 次操作时标记的点。有多测,T 组。

题目解析

我们这里称 A 经过若干次操作后不取模保持小于 N (也就是说,A+D<N)的过程叫做一轮,每一轮开始时 A 所处的点叫起点 S。可以看出,0S<D

我们发现这种标记方法的间距始终是相同的,为 D,除非遇到相同的。所以说,一旦起点确定(起点之前未被标记),这一轮之后不会遇到别的被标记的点。可以这么理解:每一轮标记的点都是 S+mD,mN。设任一标记过的起点为 S,则其标记过的点为 S+nD,nN。假设存在重合的点,则 S+mD=S+nD,即 SS=(mn)D。因为 SS0S,S<D,假设不成立。于是不存在重合的点。

那么仅存在某一轮之后与任意起点重合。并且同理可以知道,从本次重合到下一次,经过的轮数相同。具体地说,SSl=(mn)Dl 表示重合的次数,显然 l<D) 不成立。另一个性质是,每次重合的点下一个必定是未标记的。若是已标记的,则标记已覆盖完 N 个点了。

所以我们就从最开始的一次重合举例。经过多少步能重合呢?其实就是解同余方程 Dx0(modN)。想到 gcd(这种特殊情况就不必劳烦 exgcd 了)。Dx 什么时候是 N 的倍数呢?只需要提出 ND 中不存在的因数,即 N/gcd(N,D)。即: x=N/gcd(N,D)

不重合的时候,就是前进 D 了,这里不再赘述,可见代码。

一个需要注意的点是:第一次还有一个把 0 标记了的操作,所以要把 K 减一。

单次询问复杂度 O(logN),整个程序复杂度 O(TlogN)

代码实现

#include<cstring>
#include<algorithm>
#include<iostream>
#define R myio::read_int()
//也就是说之后的 R 代表的是读入的返回值
//这里省略了快读
using namespace std;
int T,N,K,D;
signed main(){
	T=myio::read_int();
	while(T--) {
		N=R,D=R,K=R-1;
		int ans1=K*D%N; //这一部分表示正常前进的
		int ans2=K/(N/__gcd(N,D)); 
		//每 N/__gcd(N,D) 步重合一次,那么就重合了 K/(N/__gcd(N,D)) 次。
		myio::print_int(ans1+ans2);
	}
	return 0;
}
posted @   robinyqc  阅读(41)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示