[AGC003E]Sequential operations on Sequence——思维题 大佬们的博客 Some Links

题目大意:

给定一个1-n的序列,每一次操作把序列无限延长之后取前面的bi位,求最后每个数字出现的次数。

思路:

首先观察到要是bi>bi+1,那么bi就是没有意义的,这样以后整个操作序列就变成了单调递增的。
考虑从反面推出每一段序列在最后的序列中的出现的次数。具体地,对于每一段序列,我们要把它划分为若干个之前的序列。
对于倒数第一次操作之后的序列它在最后的序列中出现了一次,倒数第二次操作之后的序列可以看它在最后一段序列中出现了几次,然后他的出现次数就是它在后一段序列中的出现次数*后一段序列的出现次数。显然这样还会有剩余,剩余的部分继续分成前面的序列就好了。

#include<bits/stdc++.h>

#define REP(i,a,b) for(int i=a;i<=b;++i)
#define DREP(i,a,b) for(int i=a;i>=b;--i)
typedef long long ll;

using namespace std;

void File(){
    freopen("l.in","r",stdin);
    freopen("l.out","w",stdout);
}

const int maxn=1e5+10;
int n,m,tp;
ll b[maxn],f[maxn],ans[maxn];

int main(){
    File();
    scanf("%d%d",&n,&m);
    b[++tp]=n;
    REP(i,1,m){
        scanf("%lld",&b[++tp]);
        while(tp>1 && b[tp]<b[tp-1])b[tp-1]=b[tp--];
    }
    f[tp]=1;
    DREP(i,tp-1,0){
        ll len=b[i+1];
        while(len>b[1]){
            int pos=upper_bound(b+1,b+i+1,len)-b-1;
            f[pos]+=len/b[pos]*f[i+1];
            len%=b[pos];
        }
        ans[len]+=f[i+1];
    }
    DREP(i,b[1],1)ans[i]+=ans[i+1];
    REP(i,1,n)printf("%lld\n",ans[i]);
    return 0;
}

猜你喜欢

转载自blog.csdn.net/ylsoi/article/details/81747344
今日推荐