[数论] Codeforces819D. Mister B and Astronomers

S=ai
一个人能看到第 i 个星星,那么他在下一个轮回能看到 (i+S)%T 星星。
这样的话就可以把 T 个星星,分成 gcd(S,T)个环,每个环大小为 Tgcd(S,T) ,每个人就在一个环上,那么这个人与他在环上下一个人之间的星星都是他可见的。

每个环单独出来就可以了。

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <map>
#include <vector>
#define fi first
#define se second

using namespace std;

const int N=200010;

typedef long long ll;
typedef pair<ll,ll> pari;

int n,a[N],b[N],ans[N];
ll T,S,g,len;
map<ll,vector<int> > M;
map<ll,int> C;

ll gcd(ll x,ll y){
  return y?gcd(y,x%y):x;
}

pari exgcd(ll x,ll y){
  if(!y) return pari(1,0);
  pari ret=exgcd(y,x%y);
  return pari(ret.se,ret.fi-(x/y)*ret.se);
}

inline bool cmp(const int &x,const int &y){
  return b[x]<b[y];
}

int main(){
  scanf("%lld%d",&T,&n);
  for(int i=1;i<=n;i++)
    scanf("%d",&a[i]),S+=a[i];
  a[1]=0;
  for(int i=2;i<=n;i++)
    a[i]=(a[i-1]+a[i])%T;
  g=gcd(S,T); len=T/g;
  for(int i=1;i<=n;i++){
    if(C.count(a[i])) continue;
    C[a[i]]=1;
    M[a[i]%g].push_back(i);
  }
  for(auto u : M){
    vector<int> V=u.se; int bg=u.fi;
    if(V.size()==1){
      ans[V[0]]=len; continue;
    }
    for(int i : V){
      int cur=bg-a[i],dv=(a[i]-bg)/g;
      ll A=T,B=S;
      pari now=exgcd(A,B);
      b[i]=(1LL*dv*now.se%len+len)%len;
    }
    sort(V.begin(),V.end(),cmp);
    for(int i=0;i<V.size();i++){
      int cur=V[i],nxt=V[(i+1)%V.size()];
      ans[cur]=(b[nxt]-b[cur]+len)%len;
    }
  }
  for(int i=1;i<=n;i++) printf("%d ",ans[i]);
  return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值