Mister B and Astronomers CodeForces - 819D(数论)
题目大意
有n个观察员,第一个观察员在0秒开始观察星空,随后第i个观察员会在第i-1个观察员之之后 a i a_i ai秒进行观察,第一个观察员也会在第n个观察员观察后 a 1 a_1 a1秒观察,有一颗星星其闪烁的周期为T,其第一次闪烁的时间不确定.问每个观察员有多少种可能成为第一个观察到这颗星星的人
解题思路
假设第i个观察员第一次观察的时刻为
b
i
b_i
bi,观察员的观察周期为S,则本题实际上就是求解
(
b
i
+
k
∗
s
)
%
T
=
y
(
y
∈
(
0
,
T
−
1
)
)
(b_i+k*s)\%T=y(y\in (0,T-1))
(bi+k∗s)%T=y(y∈(0,T−1))
对于每个y,使得k最小的
b
i
b_i
bi
对此我们可以对原等式进行转化
b
i
%
T
+
(
k
∗
s
)
%
T
=
y
b_i\%T+(k*s)\%T=y
bi%T+(k∗s)%T=y
其中
(
k
∗
s
)
%
T
=
q
∗
g
c
d
(
s
,
T
)
(
q
∈
Z
+
)
(k*s)\%T=q*gcd(s,T)(q\in Z^+)
(k∗s)%T=q∗gcd(s,T)(q∈Z+)先令
d
=
g
c
d
(
s
,
T
)
d=gcd(s,T)
d=gcd(s,T)因此凡是使得
b
i
%
T
%
d
=
y
%
d
b_i\%T\%d=y\%d
bi%T%d=y%d的y均可被
b
i
b_i
bi观察到,但还需要求为第一次观察到的.
继续分析.由上述的分析结果我们可以将所有的 b i % T b_i\%T bi%T分成d类由此每一类都只会在自己这一类中跳动,每类都有 T d \frac{T}{d} dT个元素
而所有的y也将分布在这些类中,因此所有的y也将分布在每类的任两个数之间
因此只需求出所有的类中的数与其下一个数之间的距离即可
其中为了方便求距离我们需要对每个数引入一个坐标,其中每个数的位置可以表示为 ( b i + k ∗ s ) % T % d = y % d ( y ∈ ( 0 , T − 1 ) ) (b_i+k*s)\%T\%d=y\%d(y\in (0,T-1)) (bi+k∗s)%T%d=y%d(y∈(0,T−1))方程的解k
AC代码
#include<bits/stdc++.h>
using namespace std;
const int sz=2e5+5;
typedef long long LL;
unordered_map<int,int> mp,id;
unordered_map<int,bool> hs;
set<int> s[sz];
int vis[sz];
int arr[sz];
int nos[sz];
int ans[sz];
LL exgcd(LL a,LL b,LL &x,LL &y)
{
if(b==0)
{
x=1,y=0;
return a;
}
LL ret=exgcd(b,a%b,y,x);
y-=a/b*x;
return ret;
}
LL getInv(LL a,LL mod)
{
LL x,y;
exgcd(a,mod,x,y);
return x;
}
int32_t main()
{
int T,n;
cin>>T>>n;
int S=0;
memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++) cin>>arr[i],S=(S+arr[i])%T;
arr[1]=0;
for(int i=2;i<=n;i++) arr[i]=(arr[i]+arr[i-1])%T;
for(int i=1;i<=n;i++) if(!hs.count(arr[i])) hs[arr[i]]=1,vis[i]=1;
int d=__gcd(S,T);
T/=d;S/=d;
int inv=getInv(S,T);
int no=0;
for(int i=1;i<=n;i++)
{
int t=arr[i]%d;
if(!id[t]) id[t]=++no;
nos[i]=1LL*inv*(arr[i]-t)/d%T;
s[id[t]].insert(nos[i]);
}
for(int i=1;i<=n;i++)
{
if(!vis[i]) {ans[i]=0;continue;}
int ids=id[arr[i]%d];
set<int>::iterator p=s[ids].find(nos[i]);
p++;
if(p==s[ids].end()) ans[i]=(*s[ids].begin())+T-nos[i];
else ans[i]=(*p)-nos[i];
}
for(int i=1;i<=n;i++) cout<<ans[i]<<' ';
}