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?
【数论|Mister B and Astronomers CodeForces - 819D(数论)】对此我们可以对原等式进行转化
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
using namespace std;
const int sz=2e5+5;
typedef long long LL;
unordered_map mp,id;
unordered_map hs;
set 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::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<
推荐阅读
- HDU 5528【2015长春现场赛 B】 Count a * b
- 类欧几里得算法|[类欧几里得算法 数论] BZOJ 2987 Earthquake
- [数论] Codeforces 819D R #421 D.Mister B and Astronomers & 516E R #292 E. Drazil and His Happy Friends
- 模板 poj2947 Widget Factory 高斯消元
- 【扩展欧几里得】练习题
- 扩展欧几里得【数论
- 数论|hdu 5322 Hope(分治+NTT)
- HDU 5528 Count a × b
- 线性同余方程组
- 数论|AtCoder Beginner Contest 156 C.Rally