AT2005-[AGC003E]Sequential operations on Sequence【差分,思維】
阿新 • • 發佈:2021-10-25
正題
題目連結:https://www.luogu.com.cn/problem/AT2005
題目大意
開始有一個\(1\sim n\)依次排列的序列,然後\(Q\)次,第\(i\)次把序列長度變為\(a_i\),不足的從前往後迴圈填充。
求最後每個數字的出現次數。
\(1\leq n,q\leq 10^5,1\leq a_i\leq 10^{18}\)
解題思路
首先肯定是先搞出一個單調棧來,然後考慮每次複製重複的部分。
考慮第\(i\)次,首先是原先的序列重複\(\lfloor\frac{a_i}{a_{i-1}}\rfloor\)次,然後後面會剩下\(a_i\%a_{i-1}\)個。
這兩個部分其實是可以分開處理的,重複的部分我們維護\(f_i\)
時間複雜度:\(O(n\log ^2n)\)
code
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=1e5+10; ll n,m,q,a[N],b[N],f[N]; void dfs(ll c,ll d){ ll x=upper_bound(a+1,a+1+m,c)-a-1; if(!x)b[c]+=d;else f[x]+=c/a[x]*d,dfs(c%a[x],d); return; } signed main() { scanf("%lld%lld",&n,&q);a[++m]=n; while(q--){ ll x;scanf("%lld",&x); while(m>0&&x<=a[m])m--; a[++m]=x; } f[m]=1; for(ll i=m;i>=2;i--) f[i-1]+=a[i]/a[i-1]*f[i],dfs(a[i]%a[i-1],f[i]); b[a[1]]+=f[1]; for(ll i=n;i>=1;i--)b[i]+=b[i+1]; for(ll i=1;i<=n;i++)printf("%lld\n",b[i]); return 0; }