zoukankan      html  css  js  c++  java
  • AT2005[AGC003E]Sequential operations on Sequence【差分,思维】

    正题

    题目链接: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\)表示第\(i\)次后的序列重复了多少次。然后对于剩下的那一部分也挺好处理的,假设长度为\(c\),那么我们就会一直重复到一个\(a_i\leq c\)的位置才会改变,而每次改变又会变成\(c\%a_i\),所以如果我们二分这个\(a_i\)的话就能做到\(O(\log^2n )\)的了,然后找到\(c<n\)的时候就是让\(1\sim c\)的次数加上一个值,差分就好了。

    时间复杂度:\(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;
    }
    
  • 相关阅读:
    8. Django系列之上传文件与下载-djang为服务端,requests为客户端
    机器学习入门15
    机器学习入门14
    机器学习入门13
    机器学习入门12
    ML
    AI
    机器学习入门11
    机器学习入门10
    机器学习入门09
  • 原文地址:https://www.cnblogs.com/QuantAsk/p/15461472.html
Copyright © 2011-2022 走看看