[agc003e]Sequential operations on Sequence

Keywords: less

Preface

Questions of classical nature are used.

The main idea of the topic

There's a number string S with an initial length of n, which is 1234... N.
There are m operations, each operation gives you a positive integer a[i], you first infinitely repeat S, and then cut out the first a[i] to become a new S.
After m operations, the number of times each number appears in S.

practice

Consider a process where solution (x, l) represents the first L bit of S after the second operation of x, and we want to get the number of times each number appears in it (this function returns an array).
Let S[i] denote the number of times each number of S occurs after the first operation (that is, the value is an array)
Obviously solve(x,l)=l/a[x-1]*S[x-1]+solve(x-1,l%a[x-1]).
We find that if l < a [x_1], it is directly equal to solve(x-1,l).
What if we find the maximum y of a [y] <= l at each step, compared with one operation like this?
There is a classical property that every module of a number is not greater than its number, only log s.
The proof is obvious.
So we just jump the log step!
So we can definitely express S[i] as S[j] whose log is less than I multiplied by the sum of some coefficients, plus a prefix of the boundary.
Then we may reverse it. If we use cnt[i] to denote the number of times S[i] calculates in the answer, we can recurse to the cnt[j] in front of us.
Finally, the prefix coefficients are marked on the array, and the answer can be obtained by sweeping the sum backwards.
What is not clear is the code implementation.

#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fd(i,a,b) for(i=a;i>=b;i--)
using namespace std;
typedef long long ll;
const int maxn=100000+10,maxtot=maxn*25;
ll ans[maxn],cnt[maxn],a[maxn],b[maxn],tree[maxtot],p[maxn][70][2];
int root[maxn],left[maxtot],right[maxtot],rk[maxn];
int len[maxn];
int i,j,k,l,t,n,m,tot,top,num;
int newnode(int x){
    tree[++tot]=tree[x];
    left[tot]=left[x];
    right[tot]=right[x];
    return tot;
}
void insert(int &x,int l,int r,int a,int b){
    x=newnode(x);
    tree[x]=b;
    if (l==r) return;
    int mid=(l+r)/2;
    if (a<=mid) insert(left[x],l,mid,a,b);else insert(right[x],mid+1,r,a,b);
}
int query(int x,int l,int r,int a,int b){
    if (!x||a>b) return 0;
    if (l==a&&r==b) return tree[x];
    int mid=(l+r)/2;
    if (b<=mid) return query(left[x],l,mid,a,b);
    else if (a>mid) return query(right[x],mid+1,r,a,b);
    else return max(query(left[x],l,mid,a,mid),query(right[x],mid+1,r,mid+1,b));
}
void solve(int x,ll l){
    int t=upper_bound(b+1,b+num+1,l)-b-1;
    int y=query(root[x-1],1,num,1,t);
    if (!y){
        if (l>=n){
            p[i][++top][0]=0;
            p[i][top][1]=l/n;
            l%=n;
        }
        p[i][++top][0]=l;
        return;
    }
    p[i][++top][0]=y;
    p[i][top][1]=l/a[y];
    solve(y,l%a[y]);
}
int main(){
    scanf("%d%d",&n,&m);
    a[0]=n;
    fo(i,1,m) scanf("%lld",&a[i]),b[i]=a[i];
    //b[++m]=n;
    sort(b+1,b+m+1);
    num=unique(b+1,b+m+1)-b-1;
    b[++num]=2000000000000000000;
    fo(i,1,m) rk[i]=lower_bound(b+1,b+num+1,a[i])-b;
    fo(i,1,m){
        root[i]=root[i-1];
        insert(root[i],1,num,rk[i],i);
    }
    fo(i,1,m){
        top=0;
        solve(i,a[i]);
        len[i]=top;
    }
    cnt[m]=1;
    fd(i,m,1){
        fo(j,1,len[i]-1)
            cnt[p[i][j][0]]+=cnt[i]*p[i][j][1];
        ans[p[i][len[i]][0]]+=cnt[i];
    }
    ans[n]+=cnt[0];
    fd(i,n,1) ans[i]+=ans[i+1];
    fo(i,1,n) printf("%lld\n",ans[i]);
}

Posted by ssj4gogita4 on Thu, 07 Feb 2019 13:12:18 -0800