#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=100005,INF=1<<30;

int dpx[MAX],dpy[MAX];

// https://kopricky.github.io/code/DataStructure_Advanced/wavelet_matrix.htmlから引用
struct BitRank {
    // block: bit 列を管理, count: block ごとに立っている 1 の数を管理
    vector<unsigned long long> block;
    vector<unsigned int> count;
    BitRank(){}
    void resize(const unsigned int num){
        block.resize(((num + 1) >> 6) + 1, 0);
        count.resize(block.size(), 0);
    }
    // i ビット目を val(0,1) にセット
    void set(const unsigned int i, const unsigned long long val){
        block[i >> 6] |= (val << (i & 63));
    }
    void build(){
        for(unsigned int i = 1; i < block.size(); i++){
            count[i] = count[i - 1] + __builtin_popcountll(block[i - 1]);
        }
    }
    // [0, i) ビットの 1 の数
    unsigned int rank1(const unsigned int i) const {
        return count[i >> 6] +
        __builtin_popcountll(block[i >> 6] & ((1ULL << (i & 63)) - 1ULL));
    }
    // [i, j) ビットの 1 の数
    unsigned int rank1(const unsigned int i, const unsigned int j) const {
        return rank1(j) - rank1(i);
    }
    // [0, i) ビットの 0 の数
    unsigned int rank0(const unsigned int i) const {
        return i - rank1(i);
    }
    // [i, j) ビットの 0 の数
    unsigned int rank0(const unsigned int i, const unsigned int j) const {
        return rank0(j) - rank0(i);
    }
};

class WaveletMatrix
{
private:
    unsigned int height;
    vector<BitRank> B;
    vector<int> pos;
public:
    WaveletMatrix(){}
    WaveletMatrix(vector<int> vec) :
    WaveletMatrix(vec, *max_element(vec.begin(), vec.end()) + 1){}
    // sigma:文字の種類数
    WaveletMatrix(vector<int> vec, const unsigned int sigma){
        init(vec, sigma);
    }
    void init(vector<int>& vec, const unsigned int sigma){
        height = (sigma == 1) ? 1 : (64 - __builtin_clzll(sigma - 1));
        B.resize(height), pos.resize(height);
        for(unsigned int i = 0; i < height; ++i){
            B[i].resize(vec.size());
            for(unsigned int j = 0; j < vec.size(); ++j) {
                B[i].set(j, get(vec[j], height - i - 1));
            }
            B[i].build();
            auto it = stable_partition(vec.begin(), vec.end(), [&](int c){
                return !get(c, height - i - 1);
            });
            pos[i] = it - vec.begin();
        }
    }
    // val の i ビット目の値を返す(0,1)
    int get(const int val, const int i){
        return val >> i & 1;
    }
    // [l, r) の間に現れる値 val の数
    int rank(const int val, const int l, const int r){
        return rank(val, r) - rank(val, l);
    }
    // [0, i) の間に現れる値 val の数
    int rank(int val, int i){
        int p = 0;
        for(unsigned int j = 0; j < height; ++j){
            if(get(val, height - j - 1)){
                p = pos[j] + B[j].rank1(p);
                i = pos[j] + B[j].rank1(i);
            }else{
                p = B[j].rank0(p);
                i = B[j].rank0(i);
            }
        }
        return i - p;
    }
    // [l, r) の k(0,1,2...) 番目に小さい値を返す
    int quantile(int k, int l, int r){
        int res = 0;
        for(unsigned int i = 0; i < height; ++i){
            const int j = B[i].rank0(l, r);
            if(j > k){
                l = B[i].rank0(l);
                r = B[i].rank0(r);
            }else{
                l = pos[i] + B[i].rank1(l);
                r = pos[i] + B[i].rank1(r);
                k -= j;
                res |= (1 << (height - i - 1));
            }
        }
        return res;
    }
    int rangefreq(const int i, const int j, const int a, const int b,
                  const int l, const int r, const int x){
        if(i == j || r <= a || b <= l) return 0;
        const int mid = (l + r) >> 1;
        if(a <= l && r <= b){
            return j - i;
        }else{
            const int left = rangefreq(B[x].rank0(i), B[x].rank0(j), a, b, l, mid, x + 1);
            const int right = rangefreq(pos[x] + B[x].rank1(i), pos[x] + B[x].rank1(j),
                                        a, b, mid, r, x + 1);
            return left + right;
        }
    }
    // [l,r) で値が [a,b) 内に含まれる数を返す
    int rangefreq(const int l, const int r, const int a, const int b){
        return rangefreq(l, r, a, b, 0, 1 << height, 0);
    }
    int rangemin(const int i, const int j, const int a, const int b,
                 const int l, const int r, const int x, const int val){
        if(i == j || r <= a || b <= l) return -1;
        if(r - l == 1) return val;
        const int mid = (l + r) >> 1;
        const int res = rangemin(B[x].rank0(i),B[x].rank0(j),a,b,l,mid,x+1,val);
        if(res < 0) return rangemin(pos[x] + B[x].rank1(i), pos[x] + B[x].rank1(j),
                                    a, b, mid, r, x + 1, val + (1 << (height - x - 1)));
        else return res;
    }
    // [l,r) で値が [a,b) 内に最小の数を返す(数が存在しない場合は -1 を返す)
    int rangemin(int l, int r, int a, int b){
        return rangemin(l, r, a, b, 0, 1 << height, 0, 0);
    }
};

template<typename T> class OrthogonalRangeCount
{
private:
    using ptt = pair<T, T>;
    const int sz;
    vector<T> X, Y;
    WaveletMatrix wm;

public:
    OrthogonalRangeCount(vector<ptt> candidate)
    : sz((int)candidate.size()), X(sz), Y(sz){
        sort(candidate.begin(), candidate.end());
        vector<int> vec(sz);
        for(int i = 0; i < sz; ++i){
            X[i] = candidate[i].first, Y[i] = candidate[i].second;
        }
        sort(Y.begin(), Y.end());
        Y.erase(unique(Y.begin(), Y.end()), Y.end());
        for(int i = 0; i < sz; ++i){
            vec[i] = lower_bound(Y.begin(), Y.end(), candidate[i].second) - Y.begin();
        }
        wm.init(vec, Y.size());

        for(int i=0;i<MAX;i++){
            dpx[i]=lower_bound(X.begin(), X.end(), i) - X.begin();
            dpy[i]=lower_bound(Y.begin(), Y.end(), i) - Y.begin();
        }
    }
    // [lx,rx) × [ly, ry) の長方形領域に含まれる点の数を答える
    int query(const T lx, const T ly, const T rx, const T ry){
        const int lxid = dpx[lx];//lower_bound(X.begin(), X.end(), lx) - X.begin();
        const int rxid = dpx[rx];//lower_bound(X.begin(), X.end(), rx) - X.begin();
        const int lyid = 0;
        const int ryid = dpy[ry];//lower_bound(Y.begin(), Y.end(), ry) - Y.begin();

        //cout<<lyid<<endl;
        if(lxid >= rxid || lyid >= ryid) return 0;
        return wm.rangefreq(lxid, rxid, lyid, ryid);
    }
};

vector<int> when[MAX];

int mem[20][MAX];

int main(){

    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);

    int N;cin>>N;
    vector<int> A(N);
    for(int i=0;i<N;i++){
        cin>>A[i];
        when[A[i]].push_back(i);
    }

    vector<pair<int,int>> vec;
    for(int i=0;i<MAX;i++){
        for(int j=0;j+1<si(when[i]);j++){
            vec.push_back(mp(when[i][j],when[i][j+1]));
        }
    }
    OrthogonalRangeCount<int> orc(vec);

    int iii=0;
    for(int k=1;k<=N;k*=2){
        for(int i=0;i<N;i++){
            int now=i;
            int left=now,right=N;
            if(k>=2) left=mem[iii-1][i]+1;
            while(right-left>1){
                int mid=(left+right)/2;

                int cnt=mid-now+1-orc.query(now,INT_MIN,mid,mid+1);
                if(cnt<=k) left=mid;
                else right=mid;
            }
            if(left>=N) left=N-1;
            mem[iii][i]=left;
        }
        iii++;
    }

    for(int j=0;j<N;j++) mem[iii][j]=N-1;

    for(int k=1;k<=N;k++){
        int j=0;
        for(int i=20;;i--){
            if(k&(1<<i)){
                j=i;
                break;
            }
        }
        int ans=0,now=0;
        while(now<N){
            int left=mem[j][now],right=mem[j+1][now]+1;
            //cout<<left<<" "<<right<<endl;
            while(right-left>1){
                int mid=(left+right)/2;

                int cnt=mid-now+1-orc.query(now,INT_MIN,mid,mid+1);
                if(cnt<=k) left=mid;
                else right=mid;
            }

            ans++;
            now=left+1;
        }
        cout<<ans<<" ";
    }
    cout<<endl;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=100005,INF=1<<30;

int dpx[MAX],dpy[MAX];

// https://kopricky.github.io/code/DataStructure_Advanced/wavelet_matrix.htmlから引用
struct BitRank {
    // block: bit 列を管理, count: block ごとに立っている 1 の数を管理
    vector<unsigned long long> block;
    vector<unsigned int> count;
    BitRank(){}
    void resize(const unsigned int num){
        block.resize(((num + 1) >> 6) + 1, 0);
        count.resize(block.size(), 0);
    }
    // i ビット目を val(0,1) にセット
    void set(const unsigned int i, const unsigned long long val){
        block[i >> 6] |= (val << (i & 63));
    }
    void build(){
        for(unsigned int i = 1; i < block.size(); i++){
            count[i] = count[i - 1] + __builtin_popcountll(block[i - 1]);
        }
    }
    // [0, i) ビットの 1 の数
    unsigned int rank1(const unsigned int i) const {
        return count[i >> 6] +
        __builtin_popcountll(block[i >> 6] & ((1ULL << (i & 63)) - 1ULL));
    }
    // [i, j) ビットの 1 の数
    unsigned int rank1(const unsigned int i, const unsigned int j) const {
        return rank1(j) - rank1(i);
    }
    // [0, i) ビットの 0 の数
    unsigned int rank0(const unsigned int i) const {
        return i - rank1(i);
    }
    // [i, j) ビットの 0 の数
    unsigned int rank0(const unsigned int i, const unsigned int j) const {
        return rank0(j) - rank0(i);
    }
};

class WaveletMatrix
{
private:
    unsigned int height;
    vector<BitRank> B;
    vector<int> pos;
public:
    WaveletMatrix(){}
    WaveletMatrix(vector<int> vec) :
    WaveletMatrix(vec, *max_element(vec.begin(), vec.end()) + 1){}
    // sigma:文字の種類数
    WaveletMatrix(vector<int> vec, const unsigned int sigma){
        init(vec, sigma);
    }
    void init(vector<int>& vec, const unsigned int sigma){
        height = (sigma == 1) ? 1 : (64 - __builtin_clzll(sigma - 1));
        B.resize(height), pos.resize(height);
        for(unsigned int i = 0; i < height; ++i){
            B[i].resize(vec.size());
            for(unsigned int j = 0; j < vec.size(); ++j) {
                B[i].set(j, get(vec[j], height - i - 1));
            }
            B[i].build();
            auto it = stable_partition(vec.begin(), vec.end(), [&](int c){
                return !get(c, height - i - 1);
            });
            pos[i] = it - vec.begin();
        }
    }
    // val の i ビット目の値を返す(0,1)
    int get(const int val, const int i){
        return val >> i & 1;
    }
    // [l, r) の間に現れる値 val の数
    int rank(const int val, const int l, const int r){
        return rank(val, r) - rank(val, l);
    }
    // [0, i) の間に現れる値 val の数
    int rank(int val, int i){
        int p = 0;
        for(unsigned int j = 0; j < height; ++j){
            if(get(val, height - j - 1)){
                p = pos[j] + B[j].rank1(p);
                i = pos[j] + B[j].rank1(i);
            }else{
                p = B[j].rank0(p);
                i = B[j].rank0(i);
            }
        }
        return i - p;
    }
    // [l, r) の k(0,1,2...) 番目に小さい値を返す
    int quantile(int k, int l, int r){
        int res = 0;
        for(unsigned int i = 0; i < height; ++i){
            const int j = B[i].rank0(l, r);
            if(j > k){
                l = B[i].rank0(l);
                r = B[i].rank0(r);
            }else{
                l = pos[i] + B[i].rank1(l);
                r = pos[i] + B[i].rank1(r);
                k -= j;
                res |= (1 << (height - i - 1));
            }
        }
        return res;
    }
    int rangefreq(const int i, const int j, const int a, const int b,
                  const int l, const int r, const int x){
        if(i == j || r <= a || b <= l) return 0;
        const int mid = (l + r) >> 1;
        if(a <= l && r <= b){
            return j - i;
        }else{
            const int left = rangefreq(B[x].rank0(i), B[x].rank0(j), a, b, l, mid, x + 1);
            const int right = rangefreq(pos[x] + B[x].rank1(i), pos[x] + B[x].rank1(j),
                                        a, b, mid, r, x + 1);
            return left + right;
        }
    }
    // [l,r) で値が [a,b) 内に含まれる数を返す
    int rangefreq(const int l, const int r, const int a, const int b){
        return rangefreq(l, r, a, b, 0, 1 << height, 0);
    }
    int rangemin(const int i, const int j, const int a, const int b,
                 const int l, const int r, const int x, const int val){
        if(i == j || r <= a || b <= l) return -1;
        if(r - l == 1) return val;
        const int mid = (l + r) >> 1;
        const int res = rangemin(B[x].rank0(i),B[x].rank0(j),a,b,l,mid,x+1,val);
        if(res < 0) return rangemin(pos[x] + B[x].rank1(i), pos[x] + B[x].rank1(j),
                                    a, b, mid, r, x + 1, val + (1 << (height - x - 1)));
        else return res;
    }
    // [l,r) で値が [a,b) 内に最小の数を返す(数が存在しない場合は -1 を返す)
    int rangemin(int l, int r, int a, int b){
        return rangemin(l, r, a, b, 0, 1 << height, 0, 0);
    }
};

template<typename T> class OrthogonalRangeCount
{
private:
    using ptt = pair<T, T>;
    const int sz;
    vector<T> X, Y;
    WaveletMatrix wm;

public:
    OrthogonalRangeCount(vector<ptt> candidate)
    : sz((int)candidate.size()), X(sz), Y(sz){
        sort(candidate.begin(), candidate.end());
        vector<int> vec(sz);
        for(int i = 0; i < sz; ++i){
            X[i] = candidate[i].first, Y[i] = candidate[i].second;
        }
        sort(Y.begin(), Y.end());
        Y.erase(unique(Y.begin(), Y.end()), Y.end());
        for(int i = 0; i < sz; ++i){
            vec[i] = lower_bound(Y.begin(), Y.end(), candidate[i].second) - Y.begin();
        }
        wm.init(vec, Y.size());

        for(int i=0;i<MAX;i++){
            dpx[i]=lower_bound(X.begin(), X.end(), i) - X.begin();
            dpy[i]=lower_bound(Y.begin(), Y.end(), i) - Y.begin();
        }
    }
    // [lx,rx) × [ly, ry) の長方形領域に含まれる点の数を答える
    int query(const T lx, const T ly, const T rx, const T ry){
        const int lxid = dpx[lx];//lower_bound(X.begin(), X.end(), lx) - X.begin();
        const int rxid = dpx[rx];//lower_bound(X.begin(), X.end(), rx) - X.begin();
        const int lyid = 0;
        const int ryid = dpy[ry];//lower_bound(Y.begin(), Y.end(), ry) - Y.begin();

        //cout<<lyid<<endl;
        if(lxid >= rxid || lyid >= ryid) return 0;
        return wm.rangefreq(lxid, rxid, lyid, ryid);
    }
};

vector<int> when[MAX];

int D=4000;
int mem[400][MAX];

int main(){

    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);

    int N;cin>>N;
    vector<int> A(N);
    for(int i=0;i<N;i++){
        cin>>A[i];
        when[A[i]].push_back(i);
    }

    vector<pair<int,int>> vec;
    for(int i=0;i<MAX;i++){
        for(int j=0;j+1<si(when[i]);j++){
            vec.push_back(mp(when[i][j],when[i][j+1]));
        }
    }
    OrthogonalRangeCount<int> orc(vec);

    int iii=0;
    for(int k=1;k<=N;k+=D){
        for(int i=0;i<N;i++){
            int now=i;
            int left=now,right=N;
            if(k>=2) left=mem[iii-1][i]+D;
            if(i) chmax(left,mem[iii][i-1]);
            while(right-left>1){
                int mid=(left+right)/2;

                int cnt=mid-now+1-orc.query(now,INT_MIN,mid,mid+1);
                if(cnt<=k) left=mid+max(0,(k-cnt-1));
                else right=mid-max(0,(cnt-k-1));
            }
            if(left>=N) left=N-1;
            mem[iii][i]=left;
        }
        iii++;
    }

    for(int i=iii;i<400;i++){
        for(int j=0;j<N;j++) mem[i][j]=N-1;
    }

    for(int k=1;k<=N;k++){
        int ans=0,now=0;
        while(now<N){
            int left=mem[(k-1)/D][now],right=mem[(k-1)/D+1][now]+1;
            //cout<<left<<" "<<right<<endl;
            while(right-left>1){
                int mid=(left+right)/2;

                int cnt=mid-now+1-orc.query(now,INT_MIN,mid,mid+1);
                if(cnt<=k) left=mid+max(0,(k-cnt-1));
                else right=mid-max(0,(cnt-k-1));
            }

            ans++;
            now=left+1;
        }
        cout<<ans<<" ";
    }
    cout<<endl;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=100005;
const ll INF=1LL<<60;

int dpx[MAX],dpy[MAX];

// https://kopricky.github.io/code/DataStructure_Advanced/wavelet_matrix.htmlから引用
struct BitRank {
    // block: bit 列を管理, count: block ごとに立っている 1 の数を管理
    vector<unsigned long long> block;
    vector<unsigned int> count;
    BitRank(){}
    void resize(const unsigned int num){
        block.resize(((num + 1) >> 6) + 1, 0);
        count.resize(block.size(), 0);
    }
    // i ビット目を val(0,1) にセット
    void set(const unsigned int i, const unsigned long long val){
        block[i >> 6] |= (val << (i & 63));
    }
    void build(){
        for(unsigned int i = 1; i < block.size(); i++){
            count[i] = count[i - 1] + __builtin_popcountll(block[i - 1]);
        }
    }
    // [0, i) ビットの 1 の数
    unsigned int rank1(const unsigned int i) const {
        return count[i >> 6] +
        __builtin_popcountll(block[i >> 6] & ((1ULL << (i & 63)) - 1ULL));
    }
    // [i, j) ビットの 1 の数
    unsigned int rank1(const unsigned int i, const unsigned int j) const {
        return rank1(j) - rank1(i);
    }
    // [0, i) ビットの 0 の数
    unsigned int rank0(const unsigned int i) const {
        return i - rank1(i);
    }
    // [i, j) ビットの 0 の数
    unsigned int rank0(const unsigned int i, const unsigned int j) const {
        return rank0(j) - rank0(i);
    }
};

class WaveletMatrix
{
private:
    unsigned int height;
    vector<BitRank> B;
    vector<int> pos;
public:
    WaveletMatrix(){}
    WaveletMatrix(vector<int> vec) :
    WaveletMatrix(vec, *max_element(vec.begin(), vec.end()) + 1){}
    // sigma:文字の種類数
    WaveletMatrix(vector<int> vec, const unsigned int sigma){
        init(vec, sigma);
    }
    void init(vector<int>& vec, const unsigned int sigma){
        height = (sigma == 1) ? 1 : (64 - __builtin_clzll(sigma - 1));
        B.resize(height), pos.resize(height);
        for(unsigned int i = 0; i < height; ++i){
            B[i].resize(vec.size());
            for(unsigned int j = 0; j < vec.size(); ++j) {
                B[i].set(j, get(vec[j], height - i - 1));
            }
            B[i].build();
            auto it = stable_partition(vec.begin(), vec.end(), [&](int c){
                return !get(c, height - i - 1);
            });
            pos[i] = it - vec.begin();
        }
    }
    // val の i ビット目の値を返す(0,1)
    int get(const int val, const int i){
        return val >> i & 1;
    }
    // [l, r) の間に現れる値 val の数
    int rank(const int val, const int l, const int r){
        return rank(val, r) - rank(val, l);
    }
    // [0, i) の間に現れる値 val の数
    int rank(int val, int i){
        int p = 0;
        for(unsigned int j = 0; j < height; ++j){
            if(get(val, height - j - 1)){
                p = pos[j] + B[j].rank1(p);
                i = pos[j] + B[j].rank1(i);
            }else{
                p = B[j].rank0(p);
                i = B[j].rank0(i);
            }
        }
        return i - p;
    }
    // [l, r) の k(0,1,2...) 番目に小さい値を返す
    int quantile(int k, int l, int r){
        int res = 0;
        for(unsigned int i = 0; i < height; ++i){
            const int j = B[i].rank0(l, r);
            if(j > k){
                l = B[i].rank0(l);
                r = B[i].rank0(r);
            }else{
                l = pos[i] + B[i].rank1(l);
                r = pos[i] + B[i].rank1(r);
                k -= j;
                res |= (1 << (height - i - 1));
            }
        }
        return res;
    }
    int rangefreq(const int i, const int j, const int a, const int b,
                  const int l, const int r, const int x){
        if(i == j || r <= a || b <= l) return 0;
        const int mid = (l + r) >> 1;
        if(a <= l && r <= b){
            return j - i;
        }else{
            const int left = rangefreq(B[x].rank0(i), B[x].rank0(j), a, b, l, mid, x + 1);
            const int right = rangefreq(pos[x] + B[x].rank1(i), pos[x] + B[x].rank1(j),
                                        a, b, mid, r, x + 1);
            return left + right;
        }
    }
    // [l,r) で値が [a,b) 内に含まれる数を返す
    int rangefreq(const int l, const int r, const int a, const int b){
        return rangefreq(l, r, a, b, 0, 1 << height, 0);
    }
    int rangemin(const int i, const int j, const int a, const int b,
                 const int l, const int r, const int x, const int val){
        if(i == j || r <= a || b <= l) return -1;
        if(r - l == 1) return val;
        const int mid = (l + r) >> 1;
        const int res = rangemin(B[x].rank0(i),B[x].rank0(j),a,b,l,mid,x+1,val);
        if(res < 0) return rangemin(pos[x] + B[x].rank1(i), pos[x] + B[x].rank1(j),
                                    a, b, mid, r, x + 1, val + (1 << (height - x - 1)));
        else return res;
    }
    // [l,r) で値が [a,b) 内に最小の数を返す(数が存在しない場合は -1 を返す)
    int rangemin(int l, int r, int a, int b){
        return rangemin(l, r, a, b, 0, 1 << height, 0, 0);
    }
};

template<typename T> class OrthogonalRangeCount
{
private:
    using ptt = pair<T, T>;
    const int sz;
    vector<T> X, Y;
    WaveletMatrix wm;

public:
    OrthogonalRangeCount(vector<ptt> candidate)
    : sz((int)candidate.size()), X(sz), Y(sz){
        sort(candidate.begin(), candidate.end());
        vector<int> vec(sz);
        for(int i = 0; i < sz; ++i){
            X[i] = candidate[i].first, Y[i] = candidate[i].second;
        }
        sort(Y.begin(), Y.end());
        Y.erase(unique(Y.begin(), Y.end()), Y.end());
        for(int i = 0; i < sz; ++i){
            vec[i] = lower_bound(Y.begin(), Y.end(), candidate[i].second) - Y.begin();
        }
        wm.init(vec, Y.size());

        for(int i=0;i<MAX;i++){
            dpx[i]=lower_bound(X.begin(), X.end(), i) - X.begin();
            dpy[i]=lower_bound(Y.begin(), Y.end(), i) - Y.begin();
        }
    }
    // [lx,rx) × [ly, ry) の長方形領域に含まれる点の数を答える
    int query(const T lx, const T ly, const T rx, const T ry){
        const int lxid = dpx[lx];//lower_bound(X.begin(), X.end(), lx) - X.begin();
        const int rxid = dpx[rx];//lower_bound(X.begin(), X.end(), rx) - X.begin();
        const int lyid = 0;
        const int ryid = dpy[ry];//lower_bound(Y.begin(), Y.end(), ry) - Y.begin();

        //cout<<lyid<<endl;
        if(lxid >= rxid || lyid >= ryid) return 0;
        return wm.rangefreq(lxid, rxid, lyid, ryid);
    }
};

vector<int> when[MAX];

int main(){

    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);

    int N;cin>>N;
    vector<int> A(N);
    for(int i=0;i<N;i++){
        cin>>A[i];
        when[A[i]].push_back(i);
    }

    vector<pair<int,int>> vec;
    for(int i=0;i<MAX;i++){
        for(int j=0;j+1<si(when[i]);j++){
            vec.push_back(mp(when[i][j],when[i][j+1]));
        }
    }
    OrthogonalRangeCount<int> orc(vec);

    for(int k=1;k<=N;k++){
        int ans=0,now=0;
        while(now<N){
            int left=now+k-1,right=N;
            while(right-left>1){
                int mid=(left+right)/2;

                int cnt=mid-now+1-orc.query(now,INT_MIN,mid,mid+1);
                if(cnt<=k) left=mid+max(0,(k-cnt-1));
                else right=mid-max(0,(cnt-k-1));
            }

            ans++;
            now=left+1;
        }
        cout<<ans<<" ";
    }
    cout<<endl;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=100005,INF=1<<30;

int dpx[MAX],dpy[MAX];

// https://kopricky.github.io/code/DataStructure_Advanced/wavelet_matrix.htmlから引用
struct BitRank {
    // block: bit 列を管理, count: block ごとに立っている 1 の数を管理
    vector<unsigned long long> block;
    vector<unsigned int> count;
    BitRank(){}
    void resize(const unsigned int num){
        block.resize(((num + 1) >> 6) + 1, 0);
        count.resize(block.size(), 0);
    }
    // i ビット目を val(0,1) にセット
    void set(const unsigned int i, const unsigned long long val){
        block[i >> 6] |= (val << (i & 63));
    }
    void build(){
        for(unsigned int i = 1; i < block.size(); i++){
            count[i] = count[i - 1] + __builtin_popcountll(block[i - 1]);
        }
    }
    // [0, i) ビットの 1 の数
    unsigned int rank1(const unsigned int i) const {
        return count[i >> 6] +
        __builtin_popcountll(block[i >> 6] & ((1ULL << (i & 63)) - 1ULL));
    }
    // [i, j) ビットの 1 の数
    unsigned int rank1(const unsigned int i, const unsigned int j) const {
        return rank1(j) - rank1(i);
    }
    // [0, i) ビットの 0 の数
    unsigned int rank0(const unsigned int i) const {
        return i - rank1(i);
    }
    // [i, j) ビットの 0 の数
    unsigned int rank0(const unsigned int i, const unsigned int j) const {
        return rank0(j) - rank0(i);
    }
};

class WaveletMatrix
{
private:
    unsigned int height;
    vector<BitRank> B;
    vector<int> pos;
public:
    WaveletMatrix(){}
    WaveletMatrix(vector<int> vec) :
    WaveletMatrix(vec, *max_element(vec.begin(), vec.end()) + 1){}
    // sigma:文字の種類数
    WaveletMatrix(vector<int> vec, const unsigned int sigma){
        init(vec, sigma);
    }
    void init(vector<int>& vec, const unsigned int sigma){
        height = (sigma == 1) ? 1 : (64 - __builtin_clzll(sigma - 1));
        B.resize(height), pos.resize(height);
        for(unsigned int i = 0; i < height; ++i){
            B[i].resize(vec.size());
            for(unsigned int j = 0; j < vec.size(); ++j) {
                B[i].set(j, get(vec[j], height - i - 1));
            }
            B[i].build();
            auto it = stable_partition(vec.begin(), vec.end(), [&](int c){
                return !get(c, height - i - 1);
            });
            pos[i] = it - vec.begin();
        }
    }
    // val の i ビット目の値を返す(0,1)
    int get(const int val, const int i){
        return val >> i & 1;
    }
    // [l, r) の間に現れる値 val の数
    int rank(const int val, const int l, const int r){
        return rank(val, r) - rank(val, l);
    }
    // [0, i) の間に現れる値 val の数
    int rank(int val, int i){
        int p = 0;
        for(unsigned int j = 0; j < height; ++j){
            if(get(val, height - j - 1)){
                p = pos[j] + B[j].rank1(p);
                i = pos[j] + B[j].rank1(i);
            }else{
                p = B[j].rank0(p);
                i = B[j].rank0(i);
            }
        }
        return i - p;
    }
    // [l, r) の k(0,1,2...) 番目に小さい値を返す
    int quantile(int k, int l, int r){
        int res = 0;
        for(unsigned int i = 0; i < height; ++i){
            const int j = B[i].rank0(l, r);
            if(j > k){
                l = B[i].rank0(l);
                r = B[i].rank0(r);
            }else{
                l = pos[i] + B[i].rank1(l);
                r = pos[i] + B[i].rank1(r);
                k -= j;
                res |= (1 << (height - i - 1));
            }
        }
        return res;
    }
    int rangefreq(const int i, const int j, const int a, const int b,
                  const int l, const int r, const int x){
        if(i == j || r <= a || b <= l) return 0;
        const int mid = (l + r) >> 1;
        if(a <= l && r <= b){
            return j - i;
        }else{
            const int left = rangefreq(B[x].rank0(i), B[x].rank0(j), a, b, l, mid, x + 1);
            const int right = rangefreq(pos[x] + B[x].rank1(i), pos[x] + B[x].rank1(j),
                                        a, b, mid, r, x + 1);
            return left + right;
        }
    }
    // [l,r) で値が [a,b) 内に含まれる数を返す
    int rangefreq(const int l, const int r, const int a, const int b){
        return rangefreq(l, r, a, b, 0, 1 << height, 0);
    }
    int rangemin(const int i, const int j, const int a, const int b,
                 const int l, const int r, const int x, const int val){
        if(i == j || r <= a || b <= l) return -1;
        if(r - l == 1) return val;
        const int mid = (l + r) >> 1;
        const int res = rangemin(B[x].rank0(i),B[x].rank0(j),a,b,l,mid,x+1,val);
        if(res < 0) return rangemin(pos[x] + B[x].rank1(i), pos[x] + B[x].rank1(j),
                                    a, b, mid, r, x + 1, val + (1 << (height - x - 1)));
        else return res;
    }
    // [l,r) で値が [a,b) 内に最小の数を返す(数が存在しない場合は -1 を返す)
    int rangemin(int l, int r, int a, int b){
        return rangemin(l, r, a, b, 0, 1 << height, 0, 0);
    }
};

template<typename T> class OrthogonalRangeCount
{
private:
    using ptt = pair<T, T>;
    const int sz;
    vector<T> X, Y;
    WaveletMatrix wm;

public:
    OrthogonalRangeCount(vector<ptt> candidate)
    : sz((int)candidate.size()), X(sz), Y(sz){
        sort(candidate.begin(), candidate.end());
        vector<int> vec(sz);
        for(int i = 0; i < sz; ++i){
            X[i] = candidate[i].first, Y[i] = candidate[i].second;
        }
        sort(Y.begin(), Y.end());
        Y.erase(unique(Y.begin(), Y.end()), Y.end());
        for(int i = 0; i < sz; ++i){
            vec[i] = lower_bound(Y.begin(), Y.end(), candidate[i].second) - Y.begin();
        }
        wm.init(vec, Y.size());

        for(int i=0;i<MAX;i++){
            dpx[i]=lower_bound(X.begin(), X.end(), i) - X.begin();
            dpy[i]=lower_bound(Y.begin(), Y.end(), i) - Y.begin();
        }
    }
    // [lx,rx) × [ly, ry) の長方形領域に含まれる点の数を答える
    int query(const T lx, const T ly, const T rx, const T ry){
        const int lxid = dpx[lx];//lower_bound(X.begin(), X.end(), lx) - X.begin();
        const int rxid = dpx[rx];//lower_bound(X.begin(), X.end(), rx) - X.begin();
        const int lyid = 0;
        const int ryid = dpy[ry];//lower_bound(Y.begin(), Y.end(), ry) - Y.begin();

        //cout<<lyid<<endl;
        if(lxid >= rxid || lyid >= ryid) return 0;
        return wm.rangefreq(lxid, rxid, lyid, ryid);
    }
};

vector<int> when[MAX];

int D=400;
int mem[400][MAX];

int main(){

    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);

    int N;cin>>N;
    vector<int> A(N);
    for(int i=0;i<N;i++){
        cin>>A[i];
        when[A[i]].push_back(i);
    }

    vector<pair<int,int>> vec;
    for(int i=0;i<MAX;i++){
        for(int j=0;j+1<si(when[i]);j++){
            vec.push_back(mp(when[i][j],when[i][j+1]));
        }
    }
    OrthogonalRangeCount<int> orc(vec);

    int iii=0;
    for(int k=1;k<=N;k+=D){
        for(int i=0;i<N;i++){
            int now=i;
            int left=now,right=N;
            if(k>=2) left=mem[iii-1][i]+D;
            if(i) chmax(left,mem[iii][i-1]);
            while(right-left>1){
                int mid=(left+right)/2;

                int cnt=mid-now+1-orc.query(now,INT_MIN,mid,mid+1);
                if(cnt<=k) left=mid+max(0,(k-cnt-1));
                else right=mid-max(0,(cnt-k-1));
            }
            if(left>=N) left=N-1;
            mem[iii][i]=left;
        }
        iii++;
    }

    for(int i=iii;i<400;i++){
        for(int j=0;j<N;j++) mem[i][j]=N-1;
    }

    for(int k=1;k<=N;k++){
        int ans=0,now=0;
        while(now<N){
            int left=mem[(k-1)/D][now],right=mem[(k-1)/D+1][now]+1;
            //cout<<left<<" "<<right<<endl;
            while(right-left>1){
                int mid=(left+right)/2;

                int cnt=mid-now+1-orc.query(now,INT_MIN,mid,mid+1);
                if(cnt<=k) left=mid+max(0,(k-cnt-1));
                else right=mid-max(0,(cnt-k-1));
            }

            ans++;
            now=left+1;
        }
        cout<<ans<<" ";
    }
    cout<<endl;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=100005;
const ll INF=1LL<<60;

int dpx[MAX],dpy[MAX];

// https://kopricky.github.io/code/DataStructure_Advanced/wavelet_matrix.htmlから引用
struct BitRank {
    // block: bit 列を管理, count: block ごとに立っている 1 の数を管理
    vector<unsigned long long> block;
    vector<unsigned int> count;
    BitRank(){}
    void resize(const unsigned int num){
        block.resize(((num + 1) >> 6) + 1, 0);
        count.resize(block.size(), 0);
    }
    // i ビット目を val(0,1) にセット
    void set(const unsigned int i, const unsigned long long val){
        block[i >> 6] |= (val << (i & 63));
    }
    void build(){
        for(unsigned int i = 1; i < block.size(); i++){
            count[i] = count[i - 1] + __builtin_popcountll(block[i - 1]);
        }
    }
    // [0, i) ビットの 1 の数
    unsigned int rank1(const unsigned int i) const {
        return count[i >> 6] +
        __builtin_popcountll(block[i >> 6] & ((1ULL << (i & 63)) - 1ULL));
    }
    // [i, j) ビットの 1 の数
    unsigned int rank1(const unsigned int i, const unsigned int j) const {
        return rank1(j) - rank1(i);
    }
    // [0, i) ビットの 0 の数
    unsigned int rank0(const unsigned int i) const {
        return i - rank1(i);
    }
    // [i, j) ビットの 0 の数
    unsigned int rank0(const unsigned int i, const unsigned int j) const {
        return rank0(j) - rank0(i);
    }
};

class WaveletMatrix
{
private:
    unsigned int height;
    vector<BitRank> B;
    vector<int> pos;
public:
    WaveletMatrix(){}
    WaveletMatrix(vector<int> vec) :
    WaveletMatrix(vec, *max_element(vec.begin(), vec.end()) + 1){}
    // sigma:文字の種類数
    WaveletMatrix(vector<int> vec, const unsigned int sigma){
        init(vec, sigma);
    }
    void init(vector<int>& vec, const unsigned int sigma){
        height = (sigma == 1) ? 1 : (64 - __builtin_clzll(sigma - 1));
        B.resize(height), pos.resize(height);
        for(unsigned int i = 0; i < height; ++i){
            B[i].resize(vec.size());
            for(unsigned int j = 0; j < vec.size(); ++j) {
                B[i].set(j, get(vec[j], height - i - 1));
            }
            B[i].build();
            auto it = stable_partition(vec.begin(), vec.end(), [&](int c){
                return !get(c, height - i - 1);
            });
            pos[i] = it - vec.begin();
        }
    }
    // val の i ビット目の値を返す(0,1)
    int get(const int val, const int i){
        return val >> i & 1;
    }
    // [l, r) の間に現れる値 val の数
    int rank(const int val, const int l, const int r){
        return rank(val, r) - rank(val, l);
    }
    // [0, i) の間に現れる値 val の数
    int rank(int val, int i){
        int p = 0;
        for(unsigned int j = 0; j < height; ++j){
            if(get(val, height - j - 1)){
                p = pos[j] + B[j].rank1(p);
                i = pos[j] + B[j].rank1(i);
            }else{
                p = B[j].rank0(p);
                i = B[j].rank0(i);
            }
        }
        return i - p;
    }
    // [l, r) の k(0,1,2...) 番目に小さい値を返す
    int quantile(int k, int l, int r){
        int res = 0;
        for(unsigned int i = 0; i < height; ++i){
            const int j = B[i].rank0(l, r);
            if(j > k){
                l = B[i].rank0(l);
                r = B[i].rank0(r);
            }else{
                l = pos[i] + B[i].rank1(l);
                r = pos[i] + B[i].rank1(r);
                k -= j;
                res |= (1 << (height - i - 1));
            }
        }
        return res;
    }
    int rangefreq(const int i, const int j, const int a, const int b,
                  const int l, const int r, const int x){
        if(i == j || r <= a || b <= l) return 0;
        const int mid = (l + r) >> 1;
        if(a <= l && r <= b){
            return j - i;
        }else{
            const int left = rangefreq(B[x].rank0(i), B[x].rank0(j), a, b, l, mid, x + 1);
            const int right = rangefreq(pos[x] + B[x].rank1(i), pos[x] + B[x].rank1(j),
                                        a, b, mid, r, x + 1);
            return left + right;
        }
    }
    // [l,r) で値が [a,b) 内に含まれる数を返す
    int rangefreq(const int l, const int r, const int a, const int b){
        return rangefreq(l, r, a, b, 0, 1 << height, 0);
    }
    int rangemin(const int i, const int j, const int a, const int b,
                 const int l, const int r, const int x, const int val){
        if(i == j || r <= a || b <= l) return -1;
        if(r - l == 1) return val;
        const int mid = (l + r) >> 1;
        const int res = rangemin(B[x].rank0(i),B[x].rank0(j),a,b,l,mid,x+1,val);
        if(res < 0) return rangemin(pos[x] + B[x].rank1(i), pos[x] + B[x].rank1(j),
                                    a, b, mid, r, x + 1, val + (1 << (height - x - 1)));
        else return res;
    }
    // [l,r) で値が [a,b) 内に最小の数を返す(数が存在しない場合は -1 を返す)
    int rangemin(int l, int r, int a, int b){
        return rangemin(l, r, a, b, 0, 1 << height, 0, 0);
    }
};

template<typename T> class OrthogonalRangeCount
{
private:
    using ptt = pair<T, T>;
    const int sz;
    vector<T> X, Y;
    WaveletMatrix wm;

public:
    OrthogonalRangeCount(vector<ptt> candidate)
    : sz((int)candidate.size()), X(sz), Y(sz){
        sort(candidate.begin(), candidate.end());
        vector<int> vec(sz);
        for(int i = 0; i < sz; ++i){
            X[i] = candidate[i].first, Y[i] = candidate[i].second;
        }
        sort(Y.begin(), Y.end());
        Y.erase(unique(Y.begin(), Y.end()), Y.end());
        for(int i = 0; i < sz; ++i){
            vec[i] = lower_bound(Y.begin(), Y.end(), candidate[i].second) - Y.begin();
        }
        wm.init(vec, Y.size());

        for(int i=0;i<MAX;i++){
            dpx[i]=lower_bound(X.begin(), X.end(), i) - X.begin();
            dpy[i]=lower_bound(Y.begin(), Y.end(), i) - Y.begin();
        }
    }
    // [lx,rx) × [ly, ry) の長方形領域に含まれる点の数を答える
    int query(const T lx, const T ly, const T rx, const T ry){
        const int lxid = dpx[lx];//lower_bound(X.begin(), X.end(), lx) - X.begin();
        const int rxid = dpx[rx];//lower_bound(X.begin(), X.end(), rx) - X.begin();
        const int lyid = 0;
        const int ryid = dpy[ry];//lower_bound(Y.begin(), Y.end(), ry) - Y.begin();

        //cout<<lyid<<endl;
        if(lxid >= rxid || lyid >= ryid) return 0;
        return wm.rangefreq(lxid, rxid, lyid, ryid);
    }
};

vector<int> when[MAX];

int main(){

    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);

    int N;cin>>N;
    vector<int> A(N);
    for(int i=0;i<N;i++){
        cin>>A[i];
        when[A[i]].push_back(i);
    }

    vector<pair<int,int>> vec;
    for(int i=0;i<MAX;i++){
        for(int j=0;j+1<si(when[i]);j++){
            vec.push_back(mp(when[i][j],when[i][j+1]));
        }
    }
    OrthogonalRangeCount<int> orc(vec);

    for(int k=1;k<=min(N,1000);k++){
        set<int> SE;
        int ans=0,now=0;
        while(now<N){
            SE.insert(A[now]);
            if(si(SE)>k){
                ans++;
                SE.clear();
                SE.insert(A[now]);
            }
            now++;
        }
        ans++;
        cout<<ans<<" ";
    }

    for(int k=1001;k<=N;k++){
        int ans=0,now=0;
        while(now<N){
            int left=now+k-1,right=N;
            while(right-left>1){
                int mid=(left+right)/2;

                int cnt=mid-now+1-orc.query(now,INT_MIN,mid,mid+1);
                if(cnt<=k) left=mid;
                else right=mid;
            }

            ans++;
            now=left+1;
        }
        cout<<ans<<" ";
    }
    cout<<endl;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=100005;
const ll INF=1LL<<60;

int dpx[MAX],dpy[MAX];

// https://kopricky.github.io/code/DataStructure_Advanced/wavelet_matrix.htmlから引用
struct BitRank {
    // block: bit 列を管理, count: block ごとに立っている 1 の数を管理
    vector<unsigned long long> block;
    vector<unsigned int> count;
    BitRank(){}
    void resize(const unsigned int num){
        block.resize(((num + 1) >> 6) + 1, 0);
        count.resize(block.size(), 0);
    }
    // i ビット目を val(0,1) にセット
    void set(const unsigned int i, const unsigned long long val){
        block[i >> 6] |= (val << (i & 63));
    }
    void build(){
        for(unsigned int i = 1; i < block.size(); i++){
            count[i] = count[i - 1] + __builtin_popcountll(block[i - 1]);
        }
    }
    // [0, i) ビットの 1 の数
    unsigned int rank1(const unsigned int i) const {
        return count[i >> 6] +
        __builtin_popcountll(block[i >> 6] & ((1ULL << (i & 63)) - 1ULL));
    }
    // [i, j) ビットの 1 の数
    unsigned int rank1(const unsigned int i, const unsigned int j) const {
        return rank1(j) - rank1(i);
    }
    // [0, i) ビットの 0 の数
    unsigned int rank0(const unsigned int i) const {
        return i - rank1(i);
    }
    // [i, j) ビットの 0 の数
    unsigned int rank0(const unsigned int i, const unsigned int j) const {
        return rank0(j) - rank0(i);
    }
};

class WaveletMatrix
{
private:
    unsigned int height;
    vector<BitRank> B;
    vector<int> pos;
public:
    WaveletMatrix(){}
    WaveletMatrix(vector<int> vec) :
    WaveletMatrix(vec, *max_element(vec.begin(), vec.end()) + 1){}
    // sigma:文字の種類数
    WaveletMatrix(vector<int> vec, const unsigned int sigma){
        init(vec, sigma);
    }
    void init(vector<int>& vec, const unsigned int sigma){
        height = (sigma == 1) ? 1 : (64 - __builtin_clzll(sigma - 1));
        B.resize(height), pos.resize(height);
        for(unsigned int i = 0; i < height; ++i){
            B[i].resize(vec.size());
            for(unsigned int j = 0; j < vec.size(); ++j) {
                B[i].set(j, get(vec[j], height - i - 1));
            }
            B[i].build();
            auto it = stable_partition(vec.begin(), vec.end(), [&](int c){
                return !get(c, height - i - 1);
            });
            pos[i] = it - vec.begin();
        }
    }
    // val の i ビット目の値を返す(0,1)
    int get(const int val, const int i){
        return val >> i & 1;
    }
    // [l, r) の間に現れる値 val の数
    int rank(const int val, const int l, const int r){
        return rank(val, r) - rank(val, l);
    }
    // [0, i) の間に現れる値 val の数
    int rank(int val, int i){
        int p = 0;
        for(unsigned int j = 0; j < height; ++j){
            if(get(val, height - j - 1)){
                p = pos[j] + B[j].rank1(p);
                i = pos[j] + B[j].rank1(i);
            }else{
                p = B[j].rank0(p);
                i = B[j].rank0(i);
            }
        }
        return i - p;
    }
    // [l, r) の k(0,1,2...) 番目に小さい値を返す
    int quantile(int k, int l, int r){
        int res = 0;
        for(unsigned int i = 0; i < height; ++i){
            const int j = B[i].rank0(l, r);
            if(j > k){
                l = B[i].rank0(l);
                r = B[i].rank0(r);
            }else{
                l = pos[i] + B[i].rank1(l);
                r = pos[i] + B[i].rank1(r);
                k -= j;
                res |= (1 << (height - i - 1));
            }
        }
        return res;
    }
    int rangefreq(const int i, const int j, const int a, const int b,
                  const int l, const int r, const int x){
        if(i == j || r <= a || b <= l) return 0;
        const int mid = (l + r) >> 1;
        if(a <= l && r <= b){
            return j - i;
        }else{
            const int left = rangefreq(B[x].rank0(i), B[x].rank0(j), a, b, l, mid, x + 1);
            const int right = rangefreq(pos[x] + B[x].rank1(i), pos[x] + B[x].rank1(j),
                                        a, b, mid, r, x + 1);
            return left + right;
        }
    }
    // [l,r) で値が [a,b) 内に含まれる数を返す
    int rangefreq(const int l, const int r, const int a, const int b){
        return rangefreq(l, r, a, b, 0, 1 << height, 0);
    }
    int rangemin(const int i, const int j, const int a, const int b,
                 const int l, const int r, const int x, const int val){
        if(i == j || r <= a || b <= l) return -1;
        if(r - l == 1) return val;
        const int mid = (l + r) >> 1;
        const int res = rangemin(B[x].rank0(i),B[x].rank0(j),a,b,l,mid,x+1,val);
        if(res < 0) return rangemin(pos[x] + B[x].rank1(i), pos[x] + B[x].rank1(j),
                                    a, b, mid, r, x + 1, val + (1 << (height - x - 1)));
        else return res;
    }
    // [l,r) で値が [a,b) 内に最小の数を返す(数が存在しない場合は -1 を返す)
    int rangemin(int l, int r, int a, int b){
        return rangemin(l, r, a, b, 0, 1 << height, 0, 0);
    }
};

template<typename T> class OrthogonalRangeCount
{
private:
    using ptt = pair<T, T>;
    const int sz;
    vector<T> X, Y;
    WaveletMatrix wm;

public:
    OrthogonalRangeCount(vector<ptt> candidate)
    : sz((int)candidate.size()), X(sz), Y(sz){
        sort(candidate.begin(), candidate.end());
        vector<int> vec(sz);
        for(int i = 0; i < sz; ++i){
            X[i] = candidate[i].first, Y[i] = candidate[i].second;
        }
        sort(Y.begin(), Y.end());
        Y.erase(unique(Y.begin(), Y.end()), Y.end());
        for(int i = 0; i < sz; ++i){
            vec[i] = lower_bound(Y.begin(), Y.end(), candidate[i].second) - Y.begin();
        }
        wm.init(vec, Y.size());

        for(int i=0;i<MAX;i++){
            dpx[i]=lower_bound(X.begin(), X.end(), i) - X.begin();
            dpy[i]=lower_bound(Y.begin(), Y.end(), i) - Y.begin();
        }
    }
    // [lx,rx) × [ly, ry) の長方形領域に含まれる点の数を答える
    int query(const T lx, const T ly, const T rx, const T ry){
        const int lxid = dpx[lx];//lower_bound(X.begin(), X.end(), lx) - X.begin();
        const int rxid = dpx[rx];//lower_bound(X.begin(), X.end(), rx) - X.begin();
        const int lyid = 0;
        const int ryid = dpy[ry];//lower_bound(Y.begin(), Y.end(), ry) - Y.begin();

        //cout<<lyid<<endl;
        if(lxid >= rxid || lyid >= ryid) return 0;
        return wm.rangefreq(lxid, rxid, lyid, ryid);
    }
};

vector<int> when[MAX];

int mem[20][MAX];

int main(){

    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);

    int N;cin>>N;
    vector<int> A(N);
    for(int i=0;i<N;i++){
        cin>>A[i];
        when[A[i]].push_back(i);
    }

    vector<pair<int,int>> vec;
    for(int i=0;i<MAX;i++){
        for(int j=0;j+1<si(when[i]);j++){
            vec.push_back(mp(when[i][j],when[i][j+1]));
        }
    }
    OrthogonalRangeCount<int> orc(vec);

    int iii=0;
    for(int k=1;k<=N;k*=2){
        for(int i=0;i<N;i++){
            int now=i;
            int left=now,right=N;
            if(k>=2) left=mem[iii-1][i]+1;
            while(right-left>1){
                int mid=(left+right)/2;

                int cnt=mid-now+1-orc.query(now,INT_MIN,mid,mid+1);
                if(cnt<=k) left=mid;
                else right=mid;
            }
            if(left>N) left=N;
            mem[iii][i]=left;
        }
        iii++;
    }

    for(int k=1;k<=N;k++){
        int j=0;
        for(int i=0;;i++){
            if(k&(1<<i)){
                j=i;
                break;
            }
        }
        int ans=0,now=0;
        while(now<N){
            int left=mem[j][now],right=N;
            while(right-left>1){
                int mid=(left+right)/2;

                int cnt=mid-now+1-orc.query(now,INT_MIN,mid,mid+1);
                if(cnt<=k) left=mid;
                else right=mid;
            }

            ans++;
            now=left+1;
        }
        cout<<ans<<" ";
    }
    cout<<endl;
}


#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
template<class T>bool chmax(T &a, const T &b) { if (a<b) { a=b; return true; } return false; }
template<class T>bool chmin(T &a, const T &b) { if (b<a) { a=b; return true; } return false; }
#define all(x) (x).begin(),(x).end()
#define fi first
#define se second
#define mp make_pair
#define si(x) int(x.size())
const int mod=1000000007,MAX=100005;
const ll INF=1LL<<60;

int dpx[MAX],dpy[MAX];

// https://kopricky.github.io/code/DataStructure_Advanced/wavelet_matrix.htmlから引用
struct BitRank {
    // block: bit 列を管理, count: block ごとに立っている 1 の数を管理
    vector<unsigned long long> block;
    vector<unsigned int> count;
    BitRank(){}
    void resize(const unsigned int num){
        block.resize(((num + 1) >> 6) + 1, 0);
        count.resize(block.size(), 0);
    }
    // i ビット目を val(0,1) にセット
    void set(const unsigned int i, const unsigned long long val){
        block[i >> 6] |= (val << (i & 63));
    }
    void build(){
        for(unsigned int i = 1; i < block.size(); i++){
            count[i] = count[i - 1] + __builtin_popcountll(block[i - 1]);
        }
    }
    // [0, i) ビットの 1 の数
    unsigned int rank1(const unsigned int i) const {
        return count[i >> 6] +
        __builtin_popcountll(block[i >> 6] & ((1ULL << (i & 63)) - 1ULL));
    }
    // [i, j) ビットの 1 の数
    unsigned int rank1(const unsigned int i, const unsigned int j) const {
        return rank1(j) - rank1(i);
    }
    // [0, i) ビットの 0 の数
    unsigned int rank0(const unsigned int i) const {
        return i - rank1(i);
    }
    // [i, j) ビットの 0 の数
    unsigned int rank0(const unsigned int i, const unsigned int j) const {
        return rank0(j) - rank0(i);
    }
};

class WaveletMatrix
{
private:
    unsigned int height;
    vector<BitRank> B;
    vector<int> pos;
public:
    WaveletMatrix(){}
    WaveletMatrix(vector<int> vec) :
    WaveletMatrix(vec, *max_element(vec.begin(), vec.end()) + 1){}
    // sigma:文字の種類数
    WaveletMatrix(vector<int> vec, const unsigned int sigma){
        init(vec, sigma);
    }
    void init(vector<int>& vec, const unsigned int sigma){
        height = (sigma == 1) ? 1 : (64 - __builtin_clzll(sigma - 1));
        B.resize(height), pos.resize(height);
        for(unsigned int i = 0; i < height; ++i){
            B[i].resize(vec.size());
            for(unsigned int j = 0; j < vec.size(); ++j) {
                B[i].set(j, get(vec[j], height - i - 1));
            }
            B[i].build();
            auto it = stable_partition(vec.begin(), vec.end(), [&](int c){
                return !get(c, height - i - 1);
            });
            pos[i] = it - vec.begin();
        }
    }
    // val の i ビット目の値を返す(0,1)
    int get(const int val, const int i){
        return val >> i & 1;
    }
    // [l, r) の間に現れる値 val の数
    int rank(const int val, const int l, const int r){
        return rank(val, r) - rank(val, l);
    }
    // [0, i) の間に現れる値 val の数
    int rank(int val, int i){
        int p = 0;
        for(unsigned int j = 0; j < height; ++j){
            if(get(val, height - j - 1)){
                p = pos[j] + B[j].rank1(p);
                i = pos[j] + B[j].rank1(i);
            }else{
                p = B[j].rank0(p);
                i = B[j].rank0(i);
            }
        }
        return i - p;
    }
    // [l, r) の k(0,1,2...) 番目に小さい値を返す
    int quantile(int k, int l, int r){
        int res = 0;
        for(unsigned int i = 0; i < height; ++i){
            const int j = B[i].rank0(l, r);
            if(j > k){
                l = B[i].rank0(l);
                r = B[i].rank0(r);
            }else{
                l = pos[i] + B[i].rank1(l);
                r = pos[i] + B[i].rank1(r);
                k -= j;
                res |= (1 << (height - i - 1));
            }
        }
        return res;
    }
    int rangefreq(const int i, const int j, const int a, const int b,
                  const int l, const int r, const int x){
        if(i == j || r <= a || b <= l) return 0;
        const int mid = (l + r) >> 1;
        if(a <= l && r <= b){
            return j - i;
        }else{
            const int left = rangefreq(B[x].rank0(i), B[x].rank0(j), a, b, l, mid, x + 1);
            const int right = rangefreq(pos[x] + B[x].rank1(i), pos[x] + B[x].rank1(j),
                                        a, b, mid, r, x + 1);
            return left + right;
        }
    }
    // [l,r) で値が [a,b) 内に含まれる数を返す
    int rangefreq(const int l, const int r, const int a, const int b){
        return rangefreq(l, r, a, b, 0, 1 << height, 0);
    }
    int rangemin(const int i, const int j, const int a, const int b,
                 const int l, const int r, const int x, const int val){
        if(i == j || r <= a || b <= l) return -1;
        if(r - l == 1) return val;
        const int mid = (l + r) >> 1;
        const int res = rangemin(B[x].rank0(i),B[x].rank0(j),a,b,l,mid,x+1,val);
        if(res < 0) return rangemin(pos[x] + B[x].rank1(i), pos[x] + B[x].rank1(j),
                                    a, b, mid, r, x + 1, val + (1 << (height - x - 1)));
        else return res;
    }
    // [l,r) で値が [a,b) 内に最小の数を返す(数が存在しない場合は -1 を返す)
    int rangemin(int l, int r, int a, int b){
        return rangemin(l, r, a, b, 0, 1 << height, 0, 0);
    }
};

template<typename T> class OrthogonalRangeCount
{
private:
    using ptt = pair<T, T>;
    const int sz;
    vector<T> X, Y;
    WaveletMatrix wm;

public:
    OrthogonalRangeCount(vector<ptt> candidate)
    : sz((int)candidate.size()), X(sz), Y(sz){
        sort(candidate.begin(), candidate.end());
        vector<int> vec(sz);
        for(int i = 0; i < sz; ++i){
            X[i] = candidate[i].first, Y[i] = candidate[i].second;
        }
        sort(Y.begin(), Y.end());
        Y.erase(unique(Y.begin(), Y.end()), Y.end());
        for(int i = 0; i < sz; ++i){
            vec[i] = lower_bound(Y.begin(), Y.end(), candidate[i].second) - Y.begin();
        }
        wm.init(vec, Y.size());

        for(int i=0;i<MAX;i++){
            dpx[i]=lower_bound(X.begin(), X.end(), i) - X.begin();
            dpy[i]=lower_bound(Y.begin(), Y.end(), i) - Y.begin();
        }
    }
    // [lx,rx) × [ly, ry) の長方形領域に含まれる点の数を答える
    int query(const T lx, const T ly, const T rx, const T ry){
        const int lxid = dpx[lx];//lower_bound(X.begin(), X.end(), lx) - X.begin();
        const int rxid = dpx[rx];//lower_bound(X.begin(), X.end(), rx) - X.begin();
        const int lyid = 0;
        const int ryid = dpy[ry];//lower_bound(Y.begin(), Y.end(), ry) - Y.begin();

        //cout<<lyid<<endl;
        if(lxid >= rxid || lyid >= ryid) return 0;
        return wm.rangefreq(lxid, rxid, lyid, ryid);
    }
};

vector<int> when[MAX];

int main(){

    std::ifstream in("text.txt");
    std::cin.rdbuf(in.rdbuf());
    cin.tie(0);
    ios::sync_with_stdio(false);

    int N;cin>>N;
    vector<int> A(N);
    for(int i=0;i<N;i++){
        cin>>A[i];
        when[A[i]].push_back(i);
    }

    vector<pair<int,int>> vec;
    for(int i=0;i<MAX;i++){
        for(int j=0;j+1<si(when[i]);j++){
            vec.push_back(mp(when[i][j],when[i][j+1]));
        }
    }
    OrthogonalRangeCount<int> orc(vec);

    for(int k=1;k<=N;k++){
        int ans=0,now=0;
        while(now<N){
            int left=now+k-1,right=N;
            while(right-left>1){
                int mid=(left+right)/2;

                int cnt=mid-now+1-orc.query(now,INT_MIN,mid,mid+1);
                if(cnt<=k) left=mid+(k-cnt);
                else right=mid-(cnt-k);
            }

            ans++;
            now=left+1;
        }
        cout<<ans<<" ";
    }
    cout<<endl;
}


#include<bits/stdc++.h>

using namespace std;
vector <int> b;
vector <vector <int> > tree, iterleft, iterright;
void build(int v, int l, int r)
{
	if(l == r)
	{
		tree[v].push_back(b[l]);
	}
	else
	{
		build(v * 2, l, (r + l) / 2);
		build(v * 2 + 1, (r + l) / 2 + 1, r);
		iterleft[v].resize(r - l + 1);
		iterright[v].resize(r - l + 1);
		int j = 0;
		for(int i = 0; i < tree[v * 2].size(); i++){
			while(j < tree[v * 2 + 1].size() && tree[v * 2 + 1][j] < tree[v * 2][i])
			{
				tree[v].push_back(tree[v * 2 + 1][j]);
				j++;
			}
			tree[v].push_back(tree[v * 2][i]);
		}
		while(j < tree[v * 2 + 1].size())
		{
			tree[v].push_back(tree[v * 2 + 1][j]);
			j++;
		}
		j = 0;
		for(int i = 0; i < tree[v].size(); i++)
		{
			while(j < tree[v * 2].size() && tree[v * 2][j] <= tree[v][i])
			{
				j++;
			}
			iterleft[v][i] = j - 1;
		}
		j = 0;
		for(int i = 0; i < tree[v].size(); i++)
		{
			while(j < tree[v * 2 + 1].size() && tree[v * 2 + 1][j] <= tree[v][i])
			{
				j++;
			}
			iterright[v][i] = j - 1;
		}
	}
}
pair <int, int> go_to(int v, int l, int r, int al, int ar, int ind, int cnt)
{
	if(l >= al && r <= ar)
	{
		if(l == r)
		{
			return {ind + 1, l};
		}
		if(ind + 1 <= cnt)
		{
			return {ind + 1, r};
		}
		int l1 = -1;
		if(ind != -1)
		{
			l1 = iterleft[v][ind];
		}
		pair <int, int> t = go_to(v * 2, l, (r + l) / 2, al, ar, l1, cnt);
		if(t.first == cnt && t.second < (r + l) / 2)
		{
			return t;
		}
		int r1 = -1;
		if(ind != -1){
			r1 = iterright[v][ind];
		}
		pair <int, int> t1 = go_to(v * 2 + 1, (r + l) / 2 + 1, r, al, ar, r1, cnt - t.first);
		if(t1.first > t.first - cnt)
		{
			return t;
		}
		return {t.first + t1.first, t1.second};
	}
	else if(l <= ar && r >= al)
	{
		int l1 = -1;
		if(ind != -1)
		{
			l1 = iterleft[v][ind];
		}
		pair <int, int> t = go_to(v * 2, l, (r + l) / 2, al, ar, l1, cnt);
		if(t.first == cnt && t.second < (r + l) / 2)
		{
			return t;
		}
		int r1 = -1;
		if(ind != -1)
		{
			r1 = iterright[v][ind];
		}
		pair <int, int> t1 =  go_to(v * 2 + 1, (r + l) / 2 + 1, r, al, ar, r1, cnt - t.first);
		if(t1.first > cnt - t.first){
			return t;
		}
		return {t1.first + t.first, t1.second};
	}
	else
	{
		return {0, -1};
	}
}
signed main() {
//	ios_base::sync_with_stdio(false);
//	cin.tie(NULL);
//	cout.tie(NULL);
	int n;
	cin >> n;
	vector <int> a(n);
	vector <int> p(n, -1);
	b.resize(n);
	for(int i = 0; i < n; i++)
	{
		cin >> a[i];
		a[i]--;
		b[i] = p[a[i]];
		p[a[i]] = i;
	}
	tree.resize(4 * n);
	iterleft.resize(4 * n);
	iterright.resize(4 * n);
	build(1, 0, n - 1);
	for(int len = 1; len <= n; len++)
	{
		int ans = 0;
		int i = 0;
		while(i < n)
		{
			int l1 = -1, r1 = tree[1].size();
			while(r1 - l1 > 1)
			{
				int midd = (r1 + l1) / 2;
				if(tree[1][midd] < i)
				{
					l1 = midd;
				}
				else
				{
					r1 = midd;
				}
			}
			i = go_to(1, 0, n - 1, i, n - 1, l1, len).second;
			i++;
			ans++;
		}
		cout << ans << " ";
	}
	return 0;
}


#include<bits/stdc++.h>

using namespace std;
vector <int> b;
vector <vector <int> > tree, iterleft, iterright;
void build(int v, int l, int r)
{
	if(l == r)
	{
		tree[v].push_back(b[l]);
	}
	else
	{
		build(v * 2, l, (r + l) / 2);
		build(v * 2 + 1, (r + l) / 2 + 1, r);
		iterleft[v].resize(r - l + 1);
		iterright[v].resize(r - l + 1);
		int j = 0;
		for(int i = 0; i < tree[v * 2].size(); i++){
			while(j < tree[v * 2 + 1].size() && tree[v * 2 + 1][j] < tree[v * 2][i])
			{
				tree[v].push_back(tree[v * 2 + 1][j]);
				j++;
			}
			tree[v].push_back(tree[v * 2][i]);
		}
		while(j < tree[v * 2 + 1].size())
		{
			tree[v].push_back(tree[v * 2 + 1][j]);
			j++;
		}
		j = 0;
		for(int i = 0; i < tree[v].size(); i++)
		{
			while(j < tree[v * 2].size() && tree[v * 2][j] <= tree[v][i])
			{
				j++;
			}
			iterleft[v][i] = j - 1;
		}
		j = 0;
		for(int i = 0; i < tree[v].size(); i++)
		{
			while(j < tree[v * 2 + 1].size() && tree[v * 2 + 1][j] <= tree[v][i])
			{
				j++;
			}
			iterright[v][i] = j - 1;
		}
	}
}
pair <int, int> go_to(int v, int l, int r, int al, int ar, int ind, int cnt)
{
	if(l >= al && r <= ar)
	{
		if(l == r)
		{
			return {ind + 1, l};
		}
		if(ind + 1 <= cnt)
		{
			return {ind + 1, r};
		}
		int l1 = -1;
		if(ind != -1)
		{
			l1 = iterleft[v][ind];
		}
		pair <int, int> t = go_to(v * 2, l, (r + l) / 2, al, ar, l1, cnt);
		if(t.first == cnt && t.second < (r + l) / 2)
		{
			return t;
		}
		int r1 = -1;
		if(ind != -1){
			r1 = iterright[v][ind];
		}
		pair <int, int> t1 = go_to(v * 2 + 1, (r + l) / 2 + 1, r, al, ar, r1, cnt - t.first);
		if(t1.first > cnt - t.first)
		{
			return t;
		}
		return {t.first + t1.first, t1.second};
	}
	else if(l <= ar && r >= al)
	{
		int l1 = -1;
		if(ind != -1)
		{
			l1 = iterleft[v][ind];
		}
		pair <int, int> t = go_to(v * 2, l, (r + l) / 2, al, ar, l1, cnt);
		if(t.first == cnt && t.second < (r + l) / 2)
		{
			return t;
		}
		int r1 = -1;
		if(ind != -1)
		{
			r1 = iterright[v][ind];
		}
		pair <int, int> t1 =  go_to(v * 2 + 1, (r + l) / 2 + 1, r, al, ar, r1, cnt - t.first);
		if(t1.first > cnt - t.first){
			return t;
		}
		return {t1.first + t.first, t1.second};
	}
	else
	{
		return {0, -1};
	}
}
signed main() {
//	ios_base::sync_with_stdio(false);
//	cin.tie(NULL);
//	cout.tie(NULL);
	int n;
	cin >> n;
	vector <int> a(n);
	vector <int> p(n, -1);
	b.resize(n);
	for(int i = 0; i < n; i++)
	{
		cin >> a[i];
		a[i]--;
		b[i] = p[a[i]];
		p[a[i]] = i;
	}
	tree.resize(4 * n);
	iterleft.resize(4 * n);
	iterright.resize(4 * n);
	build(1, 0, n - 1);
	for(int len = 1; len <= n; len++)
	{
		int ans = 0;
		int i = 0;
		while(i < n)
		{
			int l1 = -1, r1 = tree[1].size();
			while(r1 - l1 > 1)
			{
				int midd = (r1 + l1) / 2;
				if(tree[1][midd] < i)
				{
					l1 = midd;
				}
				else
				{
					r1 = midd;
				}
			}
			i = go_to(1, 0, n - 1, i, n - 1, l1, len).second;
			i++;
			ans++;
		}
		cout << ans << " ";
	}
	return 0;
}


#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 1;
const int LN = 6e6 + 1;

int root[N], ls[N], nx[N], a[N], top = 1, v;
int l[LN], r[LN], m[LN];

int als(int v, int vl, int vr, int lq, int rq, int x) {
    if (lq <= vl && vr <= rq) {
        ++top;
        m[top] = x;
        return top;
    } else if (lq >= vr || vl >= rq)
            return v;
        else {
            int u = ++top;
            l[u] = als(l[v], vl, (vl + vr) / 2, lq, rq, x);
            r[u] = als(r[v], (vl + vr) / 2, vr, lq, rq, x);
            m[u] = m[l[u]] + m[r[u]];
            return u;
        }
}

int sp(int v, int vl, int vr, int cnt) {
    if (m[v] <= cnt)
        return vr - 1;
    if (vr - vl == 1)
        if (cnt < m[v])
            return vl - 1;
        else
            return vl;
    if (m[l[v]] <= cnt)
        return sp(r[v], (vl + vr) / 2, vr, cnt - m[l[v]]);
    else
        return sp(l[v], vl, (vl + vr) / 2, cnt);

}

int main() {
    int i, j, k, n;
    //freopen("input.txt", "r", stdin);
    //freopen("test.txt", "r", stdin);
    //freopen("test1.txt", "w", stdout);
    ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin >> n;
    v = 1;
    while (v < n) v *= 2;
    root[1] = 1;
    for (i = 1; i <= n; ++i) {
        cin >> a[i];
        if (ls[a[i]] != 0)
            nx[ls[a[i]]] = i;
        else
            root[1] = als(root[1], 1, v + 1, i, i + 1, 1);
        ls[a[i]] = i;
    }
    for (i = 2; i <= n; ++i) {
        root[i] = als(root[i - 1], 1, v + 1, i - 1, i, 0);
        root[i] = als(root[i], 1, v + 1, nx[i - 1], nx[i - 1] + 1, 1);
    }
    for (i = 1; i <= n; ++i) {
        j = 1;
        int ans = 0;
        while (j <= n) {
            ++ans;
            j = sp(root[j], 1, v + 1, i) + 1;
        }
        cout << ans << ' ';
    }
}


#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 1;
const int LN = 2e6 + 1;

int root[N], ls[N], nx[N], a[N], top = 1, v;
int l[LN], r[LN], m[LN];

int als(int v, int vl, int vr, int lq, int rq, int x) {
    if (lq <= vl && vr <= rq) {
        ++top;
        m[top] = x;
        return top;
    } else if (lq >= vr || vl >= rq)
            return v;
        else {
            int u = ++top;
            l[u] = als(l[v], vl, (vl + vr) / 2, lq, rq, x);
            r[u] = als(r[v], (vl + vr) / 2, vr, lq, rq, x);
            m[u] = m[l[u]] + m[r[u]];
            return u;
        }
}

int sum(int v, int vl, int vr, int lq, int rq) {
    if (lq <= vl && vr <= rq)
        return m[v];
    else if (lq >= vr || vl >= rq)
            return 0;
        else
            return sum(l[v], vl, (vl + vr) / 2, lq, rq) + sum(r[v], (vl + vr) / 2, vr, lq, rq);
}

int main() {
    int i, j, k, n;
    //freopen("input.txt", "r", stdin);
    ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin >> n;
    v = 1;
    while (v < n) v *= 2;
    root[1] = 1;
    for (i = 1; i <= n; ++i) {
        cin >> a[i];
        if (ls[a[i]] != 0)
            nx[ls[a[i]]] = i;
        else
            root[1] = als(root[1], 1, v + 1, i, i + 1, 1);
        ls[a[i]] = i;
    }
    for (i = 2; i <= n; ++i) {
        root[i] = als(root[i - 1], 1, v + 1, i - 1, i, 0);
        root[i] = als(root[i], 1, v + 1, nx[i - 1], nx[i - 1] + 1, 1);
    }
    for (i = 1; i <= n; ++i) {
        j = 1;
        int ans = 0;
        while (j <= n) {
            ++ans;
            int l = j, r = n + 1;
            while (r - l > 1) {
                int mid = (l + r) / 2;
                if (sum(root[j], 1, v + 1, j, mid + 1) > i)
                    r = mid;
                else
                    l = mid;
            }
            j = r;
        }
        cout << ans << ' ';
    }
}


#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 1;
const int LN = 2e6 + 1;

int root[N], ls[N], nx[N], a[N], top = 1, v;
int l[LN], r[LN], m[LN];

int als(int v, int vl, int vr, int lq, int rq, int x) {
    if (lq <= vl && vr <= rq) {
        ++top;
        m[top] = x;
        return top;
    } else if (lq >= vr || vl >= rq)
            return v;
        else {
            int u = ++top;
            l[u] = als(l[v], vl, (vl + vr) / 2, lq, rq, x);
            r[u] = als(r[v], (vl + vr) / 2, vr, lq, rq, x);
            m[u] = m[l[u]] + m[r[u]];
            return u;
        }
}

int sum(int v, int vl, int vr, int lq, int rq) {
    if (lq <= vl && vr <= rq)
        return m[v];
    else if (lq >= vr || vl >= rq)
            return 0;
        else
            return sum(l[v], vl, (vl + vr) / 2, lq, rq) + sum(r[v], (vl + vr) / 2, vr, lq, rq);
}

int main() {
    int i, j, k, n;
    //freopen("input.txt", "r", stdin);
    ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin >> n;
    v = 1;
    while (v < n) v *= 2;
    root[1] = 1;
    for (i = 1; i <= n; ++i) {
        cin >> a[i];
        if (ls[a[i]] != 0)
            nx[ls[a[i]]] = i;
        else
            root[1] = als(root[1], 1, v + 1, i, i + 1, 1);
        ls[a[i]] = i;
    }
    for (i = 2; i <= n; ++i) {
        root[i] = als(root[i - 1], 1, v + 1, i - 1, i, 0);
        root[i] = als(root[i], 1, v + 1, nx[i - 1], nx[i - 1] + 1, 1);
    }
    for (i = 1; i <= n; ++i) {
        j = 1;
        int ans = 0;
        while (j <= n) {
            ++ans;
            int l = j, r = n + 1;
            while (r - l > 1) {
                int mid = (l + r) / 2;
                if (sum(root[j], 1, v + 1, l, mid + 1) > i)
                    r = mid;
                else
                    l = mid;
            }
            j = r;
        }
        cout << ans << ' ';
    }
}


#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 1;
const int LN = 6e6 + 1;

int root[N], ls[N], nx[N], a[N], top = 1, v;
int l[LN], r[LN], m[LN];

int als(int v, int vl, int vr, int lq, int rq, int x) {
    if (lq <= vl && vr <= rq) {
        ++top;
        m[top] = x;
        return top;
    } else if (lq >= vr || vl >= rq)
            return v;
        else {
            int u = ++top;
            l[u] = als(l[v], vl, (vl + vr) / 2, lq, rq, x);
            r[u] = als(r[v], (vl + vr) / 2, vr, lq, rq, x);
            m[u] = m[l[u]] + m[r[u]];
            return u;
        }
}

int sum(int v, int vl, int vr, int lq, int rq) {
    if (lq <= vl && vr <= rq)
        return m[v];
    else if (lq >= vr || vl >= rq)
            return 0;
        else
            return sum(l[v], vl, (vl + vr) / 2, lq, rq) + sum(r[v], (vl + vr) / 2, vr, lq, rq);
}

int main() {
    int i, j, k, n;
    //freopen("input.txt", "r", stdin);
    ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0);
    cin >> n;
    v = 1;
    while (v < n) v *= 2;
    root[1] = 1;
    for (i = 1; i <= n; ++i) {
        cin >> a[i];
        if (ls[a[i]] != 0)
            nx[ls[a[i]]] = i;
        else
            root[1] = als(root[1], 1, v + 1, i, i + 1, 1);
        ls[a[i]] = i;
    }
    for (i = 2; i <= n; ++i) {
        root[i] = als(root[i - 1], 1, v + 1, i - 1, i, 0);
        root[i] = als(root[i], 1, v + 1, nx[i - 1], nx[i - 1] + 1, 1);
    }
    for (i = 1; i <= n; ++i) {
        j = 1;
        int ans = 0;
        while (j <= n) {
            ++ans;
            int l = j, r = n + 1;
            while (r - l > 1) {
                int mid = (l + r) / 2;
                if (sum(root[j], 1, v + 1, j, mid + 1) > i)
                    r = mid;
                else
                    l = mid;
            }
            j = r;
        }
        cout << ans << ' ';
    }
}


#include <bits/stdc++.h>

#define _USE_MATH_DEFINES
#define F first
#define S second
#define forn(i, n) for (int i = 0; i < int(n); i++)
#define remax(x, y) (x) = max((x), (y))
#define remin(x, y) (x) = min((x), (y))

using namespace std;

using ll = long long;
using pi = pair<int, int>;
using pll = pair<ll, ll>;

int n;
vector<int> a;
vector<vector<int>> idx;

int next_idx(int i) {
    vector<int>& v = idx[a[i]];
    auto it = upper_bound(v.begin(), v.end(), i);
    return it == v.end() ? n : *it;
}

struct node {
    int s;
    node* lc;
    node* rc;

    node() : s(0), lc(nullptr), rc(nullptr) {}

    node* copy() const {
        node* N = new node();
        N->s = s;
        N->lc = lc ? lc : new node();
        N->rc = rc ? rc : new node();
        return N;
    }

    node* inc(int L, int R, int pos, int x) const {
        node* N = copy();
        if (L == R)
            N->s += x;
        else {
            int LE = (L + R) / 2;
            if (pos <= LE)
                N->lc = N->lc->inc(L, LE, pos, x);
            else
                N->rc = N->rc->inc(LE + 1, R, pos, x);
            N->s = N->lc->s + N->rc->s;
        }
        return N;
    }

    int rsq(int L, int R, int lq, int rq) const {
        if (R < lq || rq < L)
            return 0;
        if (lq <= L && R <= rq)
            return s;
        int LE = (L + R) / 2;
        int ans = 0;
        if (lc)
            ans += lc->rsq(L, LE, lq, rq);
        if (rc)
            ans += rc->rsq(LE + 1, R, lq, rq);
        return ans;
    }

    // Returns the smallest index pos such that rsq(0, pos) is strictly
    // greater than k (n if no such index exists)
    int idx(int L, int R, int k) const {
        if (k >= s)
            return R + 1;
        if (L == R)
            return L;
        int LE = (L + R) / 2;
        int ls = lc ? lc->s : 0;
        if (ls <= k)
            return rc->idx(LE + 1, R, k - ls);
        else
            return lc->idx(L, LE, k);
    }
};

int main() {
    ios_base::sync_with_stdio(false);
    cout << setprecision(12);
    cin.tie(nullptr);

    cin >> n;

    a.resize(n);
    forn(i, n)
        cin >> a[i], a[i]--;

    idx.resize(n);
    forn(i, n)
        idx[a[i]].push_back(i);

    vector<node*> versions(n + 1);
    versions[n] = new node();
    for (int i = n - 1; i >= 0; i--) {
        versions[i] = versions[i + 1];
        int j = next_idx(i);
        if (j < n)
            versions[i] = versions[i]->inc(0, n - 1, j, -1);
        versions[i] = versions[i]->inc(0, n - 1, i, 1);
    }

    for (int k = 1; k <= n; k++) {
        int i = 0, p = 0;
        while (i < n) {
            i = versions[i]->idx(0, n - 1, k);
            p++;
        }
        cout << p << " ";
    }
    cout << endl;
}


#include <bits/stdc++.h>

#define _USE_MATH_DEFINES
#define F first
#define S second
#define forn(i, n) for (int i = 0; i < int(n); i++)
#define remax(x, y) (x) = max((x), (y))
#define remin(x, y) (x) = min((x), (y))

using namespace std;

using ll = long long;
using pi = pair<int, int>;
using pll = pair<ll, ll>;

int n;
vector<int> a, nxt;

struct node {
    int s;
    node* lc;
    node* rc;

    node() : s(0), lc(nullptr), rc(nullptr) {}
};

int val(node* N) {
    return N ? N->s : 0;
}

node* inc(node* N, int L, int R, int pos, int x) {
    if (N)
        N = new node(*N);
    else
        N = new node();
    if (L == R)
        N->s += x;
    else {
        int LE = (L + R) / 2;
        if (pos <= LE)
            N->lc = inc(N->lc, L, LE, pos, x);
        else
            N->rc = inc(N->rc, LE + 1, R, pos, x);
        N->s = val(N->lc) + val(N->rc);
    }
    return N;
}

int lb(node* N, int L, int R, int k) {
    if (L == R)
        return L;
    int LE = (L + R) / 2;
    int ls = val(N->lc);
    if (ls <= k)
        return lb(N->rc, LE + 1, R, k - ls);
    else
        return lb(N->lc, L, LE, k);
}

int main() {
    ios_base::sync_with_stdio(false);
    cout << setprecision(12);
    cin.tie(nullptr);

    cin >> n;

    a.resize(n);
    forn(i, n)
        cin >> a[i], a[i]--;

    nxt.resize(n);
    vector<int> last(n, n);
    for (int i = n - 1; i >= 0; i--) {
        nxt[i] = last[a[i]];
        last[a[i]] = i;
    }

    vector<node*> versions(n + 1);
    versions[n] = new node();
    for (int i = n - 1; i >= 0; i--) {
        versions[i] = versions[i + 1];
        int j = nxt[i];
        if (j < n)
            versions[i] = inc(versions[i], 0, n, j, -1);
        versions[i] = inc(versions[i], 0, n, i, 1);
    }

    for (int k = 1; k <= n; k++) {
        int i = 0, p = 0;
        while (i < n) {
            i = lb(versions[i], 0, n, k);
            p++;
        }
        cout << p << " ";
    }
    cout << endl;
}


#include <bits/stdc++.h>

#define _USE_MATH_DEFINES
#define F first
#define S second
#define forn(i, n) for (int i = 0; i < int(n); i++)
#define remax(x, y) (x) = max((x), (y))
#define remin(x, y) (x) = min((x), (y))
#define zin(var) int var; cin >> var; var--;

using namespace std;

using ll = long long;
using pi = pair<int, int>;
using pll = pair<ll, ll>;

void inc(vector<int>& f, int i, int x) {
    for (; i < (int) f.size(); i |= i + 1)
        f[i] += x;
}

int upper_bound(vector<int>& f, int k) {
    int i = 0, s = 0;
    for (int b = f.size() / 2; b > 0; b /= 2) {
        if (s + f[i + b - 1] <= k) {
            s += f[i + b - 1];
            i += b;
        }
    }
    return i;
}

int main() {
    ios_base::sync_with_stdio(false);
    cout << setprecision(12);
    cin.tie(nullptr);

    int n;
    cin >> n;

    vector<int> a(n);
    forn(i, n)
        cin >> a[i], a[i]--;

    vector<int> fst(n, n), nxt(n);
    for (int i = n - 1; i >= 0; i--) {
        nxt[i] = fst[a[i]];
        fst[a[i]] = i;
    }

    int B = 1;
    while (B <= n)
        B *= 2;

    vector<int> f(B);
    forn(i, n)
        inc(f, fst[i], 1);

    vector<int> query[n];
    for (int k = 1; k <= n; k++)
        query[0].push_back(k);

    vector<int> ans(n);
    forn(i, n) {
        for (int k : query[i]) {
            ans[k - 1]++;
            int j = upper_bound(f, k);
            if (j < n)
                query[j].push_back(k);
        }
        inc(f, i, -1);
        if (nxt[i] < n)
            inc(f, nxt[i], 1);
    }

    for (int p : ans)
        cout << p << " ";
    cout << endl;
}


#include <bits/stdc++.h>

#define _USE_MATH_DEFINES
#define F first
#define S second
#define forn(i, n) for (int i = 0; i < int(n); i++)
#define remax(x, y) (x) = max((x), (y))
#define remin(x, y) (x) = min((x), (y))

using namespace std;

using ll = long long;
using pi = pair<int, int>;
using pll = pair<ll, ll>;

int n;
vector<int> a;
vector<vector<int>> idx;

int next_idx(int i) {
    vector<int>& v = idx[a[i]];
    auto it = upper_bound(v.begin(), v.end(), i);
    return it == v.end() ? n : *it;
}

struct node {
    int s;
    node* lc;
    node* rc;

    node() : s(0), lc(nullptr), rc(nullptr) {}
};

int val(node* N) {
    return N ? N->s : 0;
}

node* inc(node* N, int L, int R, int pos, int x) {
    if (N)
        N = new node(*N);
    else
        N = new node();
    if (L == R)
        N->s += x;
    else {
        int LE = (L + R) / 2;
        if (pos <= LE)
            N->lc = inc(N->lc, L, LE, pos, x);
        else
            N->rc = inc(N->rc, LE + 1, R, pos, x);
        N->s = val(N->lc) + val(N->rc);
    }
    return N;
}

int lb(node* N, int L, int R, int k) {
    if (L == R)
        return L;
    int LE = (L + R) / 2;
    int ls = val(N->lc);
    if (ls <= k)
        return lb(N->rc, LE + 1, R, k - ls);
    else
        return lb(N->lc, L, LE, k);
}

int main() {
    ios_base::sync_with_stdio(false);
    cout << setprecision(12);
    cin.tie(nullptr);

    cin >> n;

    a.resize(n);
    forn(i, n)
        cin >> a[i], a[i]--;

    idx.resize(n);
    forn(i, n)
        idx[a[i]].push_back(i);

    vector<node*> versions(n + 1);
    versions[n] = new node();
    for (int i = n - 1; i >= 0; i--) {
        versions[i] = versions[i + 1];
        int j = next_idx(i);
        if (j < n)
            versions[i] = inc(versions[i], 0, n, j, -1);
        versions[i] = inc(versions[i], 0, n, i, 1);
    }

    for (int k = 1; k <= n; k++) {
        int i = 0, p = 0;
        while (i < n) {
            i = lb(versions[i], 0, n, k);
            p++;
        }
        cout << p << " ";
    }
    cout << endl;
}


#include <bits/stdc++.h>

#define _USE_MATH_DEFINES
#define F first
#define S second
#define forn(i, n) for (int i = 0; i < int(n); i++)
#define remax(x, y) (x) = max((x), (y))
#define remin(x, y) (x) = min((x), (y))

using namespace std;

using ll = long long;
using pi = pair<int, int>;
using pll = pair<ll, ll>;

int n;
vector<int> a;

int l, r, uniq;
vector<int> ans, cnt;

void inc_l() {
    if (--cnt[a[l++]] == 0)
        uniq--;
}

void inc_r() {
    if (cnt[a[++r]]++ == 0)
        uniq++;
}

void dec_l() {
    if (cnt[a[--l]]++ == 0)
        uniq++;
}

void dec_r() {
    if (--cnt[a[r--]] == 0)
        uniq--;
}

int icount(int k) {
    l = 0, r = -1, uniq = 0;
    cnt.assign(n, 0);

    int p = 0;
    for (; r < n; p++) {
        while (uniq <= k && r < n)
            inc_r();
        while (l < r)
            inc_l();
    }
    return p;
}

void bcount(int k0) {
    queue<array<int, 3>> q;
    for (int k = k0; k <= n; k++)
        q.push({0, k, 1});

    while (!q.empty()) {
        array<int, 3> e = q.front();
        q.pop();

        int lq = e[0], k = e[1], p = e[2];

        while (l > lq)
            dec_l();
        while (l < lq)
            inc_l();
        while (uniq >= k)
            dec_r();
        while (uniq <= k && r < n)
            inc_r();

        if (r == n)
            ans[k - 1] = p;
        else
            q.push({r, k, p + 1});
    }
}

int main() {
    ios_base::sync_with_stdio(false);
    cout << setprecision(12);
    cin.tie(nullptr);

    cin >> n;

    a.resize(n);
    forn(i, n)
        cin >> a[i], a[i]--;

    ans.resize(n);
    cnt.resize(n);

    int k0 = sqrt(n);
    for (int k = 1; k < k0; k++)
        ans[k - 1] = icount(k);
    bcount(k0);

    for (int x : ans)
        cout << x << " ";
    cout << endl;
}


#include <bits/stdc++.h>

#define _USE_MATH_DEFINES
#define F first
#define S second
#define forn(i, n) for (int i = 0; i < int(n); i++)
#define remax(x, y) (x) = max((x), (y))
#define remin(x, y) (x) = min((x), (y))
#define zin(var) int var; cin >> var; var--;

using namespace std;

using ll = long long;
using pi = pair<int, int>;
using pll = pair<ll, ll>;

struct Node {
    int S, LV, RV;

    Node() : S(0), LV(0), RV(0) {}
    Node(int S, int LV, int RV) : S(S), LV(LV), RV(RV) {}

    void merge(int);
};

int B;
vector<vector<Node>> t;

void Node::merge(int i) {
    S = t[2 * i].back().S + t[2 * i + 1].back().S;
}

void inc(int pos, int x) {
    int i = B + pos;
    t[i].push_back(Node(t[i].back().S + x, 0, 0));
    for (; i > 1; i /= 2) {
        int V = t[i].size() - 1;
        int p = i / 2;
        t[p].push_back(Node(t[p].back()));
        t[p].back().S += x;
        if (i & 1)
            t[p].back().RV = V;
        else
            t[p].back().LV = V;
    }
}

int upper_bound(int i, int L, int R, int k, int V) {
    if (L == R)
        return L;
    int LE = (L + R) / 2;
    int LV = t[i][V].LV;
    int RV = t[i][V].RV;
    int LS = t[2 * i][LV].S;
    if (k < LS)
        return upper_bound(2 * i, L, LE, k, LV);
    else
        return upper_bound(2 * i + 1, LE + 1, R, k - LS, RV);
}

int main() {
    ios_base::sync_with_stdio(false);
    cout << setprecision(12);
    cin.tie(nullptr);

    int n;
    cin >> n;

    vector<int> a(n);
    forn(i, n)
        cin >> a[i], a[i]--;

    vector<int> last_idx(n, n), next_idx(n);
    for (int i = n - 1; i >= 0; i--) {
        next_idx[i] = last_idx[a[i]];
        last_idx[a[i]] = i;
    }

    B = 1;
    while (B <= n)
        B *= 2;
    t.assign(2 * B, vector<Node>(1));

    vector<int> version(n);
    for (int i = n - 1; i >= 0; i--) {
        if (next_idx[i] < n)
            inc(next_idx[i], -1);
        inc(i, 1);
        version[i] = t[1].size() - 1;
    }

    for (int k = 1; k <= n; k++) {
        int i = 0, p = 0;
        while (i < n) {
            i = upper_bound(1, 0, B - 1, k, version[i]);
            p++;
        }
        cout << p << " ";
    }
    cout << endl;
}


#include <bits/stdc++.h>

#define _USE_MATH_DEFINES
#define F first
#define S second
#define forn(i, n) for (int i = 0; i < int(n); i++)
#define remax(x, y) (x) = max((x), (y))
#define remin(x, y) (x) = min((x), (y))

using namespace std;

using ll = long long;
using pi = pair<int, int>;
using pll = pair<ll, ll>;

int n;
vector<int> a;

int l, r, uniq;
vector<int> ans, cnt;

void reset(int i) {
    l = i;
    r = i - 1;
    uniq = 0;
    cnt.assign(n + 1, 0);
}

void inc_l() {
    if (--cnt[a[l++]] == 0)
        uniq--;
}

void inc_r() {
    if (cnt[a[++r]]++ == 0)
        uniq++;
}

void icount(int k) {
    reset(0);
    for (; r < n; ans[k - 1]++) {
        while (uniq <= k && r < n)
            inc_r();
        while (l < r)
            inc_l();
    }
}

void bcount(int k0) {
    queue<pi> q;
    for (int k = k0; k <= n; k++)
        q.emplace(0, k);
    while (!q.empty()) {
        pi p = q.front();
        q.pop();
        int lq = p.F, k = p.S;
        if (k == k0)
            reset(lq);
        while (l < lq)
            inc_l();
        while (uniq <= k && r < n)
            inc_r();
        if (r < n)
            q.emplace(r, k);
        ans[k - 1]++;
    }
}

int main() {
    ios_base::sync_with_stdio(false);
    cout << setprecision(12);
    cin.tie(nullptr);

    cin >> n;

    a.resize(n + 1);
    forn(i, n)
        cin >> a[i];

    ans.resize(n);

    int k0 = sqrt(n);
    for (int k = 1; k < k0; k++)
        icount(k);
    bcount(k0);

    for (int x : ans)
        cout << x << " ";
    cout << endl;
}


#include <bits/stdc++.h>

#define _USE_MATH_DEFINES
#define F first
#define S second
#define forn(i, n) for (int i = 0; i < int(n); i++)
#define remax(x, y) (x) = max((x), (y))
#define remin(x, y) (x) = min((x), (y))
#define zin(var) int var; cin >> var; var--;

using namespace std;

using ll = long long;
using pi = pair<int, int>;
using pll = pair<ll, ll>;

void inc(vector<int>& f, int i, int x) {
    for (; i < (int) f.size(); i |= i + 1)
        f[i] += x;
}

int upper_bound(vector<int>& f, int k) {
    int i = 0, s = 0;
    for (int b = f.size(); b > 0; b /= 2) {
        if (s + f[i + b - 1] <= k) {
            s += f[i + b - 1];
            i += b;
        }
    }
    return i;
}

int main() {
    ios_base::sync_with_stdio(false);
    cout << setprecision(12);
    cin.tie(nullptr);

    int n;
    cin >> n;

    vector<int> a(n);
    forn(i, n)
        cin >> a[i], a[i]--;

    vector<int> fst(n, n), nxt(n);
    for (int i = n - 1; i >= 0; i--) {
        nxt[i] = fst[a[i]];
        fst[a[i]] = i;
    }

    int B = 1;
    while (B <= n)
        B *= 2;

    vector<int> f(B);
    forn(i, n)
        inc(f, fst[i], 1);

    vector<int> query[n];
    for (int k = 1; k <= n; k++)
        query[0].push_back(k);

    vector<int> ans(n);
    forn(i, n) {
        for (int k : query[i]) {
            ans[k - 1]++;
            int j = upper_bound(f, k);
            if (j < n)
                query[j].push_back(k);
        }
        inc(f, i, -1);
        if (nxt[i] < n)
            inc(f, nxt[i], 1);
    }

    for (int p : ans)
        cout << p << " ";
    cout << endl;
}


#include <bits/stdc++.h>

#define _USE_MATH_DEFINES
#define F first
#define S second
#define forn(i, n) for (int i = 0; i < int(n); i++)
#define remax(x, y) (x) = max((x), (y))
#define remin(x, y) (x) = min((x), (y))

using namespace std;

using ll = long long;
using pi = pair<int, int>;
using pll = pair<ll, ll>;

int n;
vector<int> a;

int l, r, uniq;
vector<int> ans, cnt;

void inc_l() {
    if (--cnt[a[l++]] == 0)
        uniq--;
}

void inc_r() {
    if (cnt[a[++r]]++ == 0)
        uniq++;
}

void dec_l() {
    if (cnt[a[--l]]++ == 0)
        uniq++;
}

void dec_r() {
    if (--cnt[a[r--]] == 0)
        uniq--;
}

int icount(int k) {
    l = 0, r = -1, uniq = 0;
    cnt.assign(n, 0);

    int p = 0;
    for (; r < n; p++) {
        while (uniq <= k && r < n)
            inc_r();
        while (l < r)
            inc_l();
    }
    return p;
}

void bcount(int k0) {
    queue<array<int, 3>> q;
    for (int k = k0; k <= n; k++)
        q.push({0, k, 1});

    while (!q.empty()) {
        array<int, 3> e = q.front();
        q.pop();

        int lq = e[0], k = e[1], p = e[2];

        while (l > lq)
            dec_l();
        while (l < lq)
            inc_l();
        while (uniq >= k)
            dec_r();
        while (uniq <= k && r < n)
            inc_r();

        if (r == n)
            ans[k - 1] = p;
        else
            q.push({r, k, p + 1});
    }
}

int main() {
    ios_base::sync_with_stdio(false);
    cout << setprecision(12);
    cin.tie(nullptr);

    cin >> n;

    a.resize(n + 1);
    forn(i, n)
        cin >> a[i], a[i]--;
    a[n] = n;

    cnt.resize(n + 1);

    ans.resize(n);
    int k0 = sqrt(n);
    for (int k = 1; k < k0; k++)
        ans[k - 1] = icount(k);
    bcount(k0);

    for (int x : ans)
        cout << x << " ";
    cout << endl;
}


#include <bits/stdc++.h>

using namespace std;

struct PersistentNonLazySegmentTree
{
    #define type int
    #define Mid ((L + R) >> 1)

    private : const type E = 0;     /// identity element    /// Check this
    private : static const int Nax = 100 * 100100;          /// Check this

    private : int n;        /// Array length
    private : int Counter;  /// Counter for nodes

    private : int Left[Nax];
    private : int Right[Nax];
    private : type Tree[Nax];
    private : vector <int> Roots;

    private : int NewNode()
    {
        Tree[Counter] = E;
        Left[Counter] = -1;
        Right[Counter] = -1;

        return Counter++;
    }

    private : int NewNode(int Copy)
    {
        Tree[Counter] = Tree[Copy];
        Left[Counter] = Left[Copy];
        Right[Counter] = Right[Copy];

        return Counter++;
    }

    private : type Unite(type x, type y)    /// Check this
    {
        return x + y;
    }

    private : void Merge(int Node)
    {
        Tree[Node] = Unite(Tree[Left[Node]], Tree[Right[Node]]);
    }

    public : int Build(const vector <type>& a)
    {
        Clear();
        n = a.size();
        Roots.push_back(NewNode());
        Build(a, Roots[0], 0, n - 1);
        return (int) Roots.size() - 1;
    }

    private : void Build(const vector <type>& a, int Node, int L, int R)
    {
        if(L == R)  return void(Tree[Node] = a[L]);

        Build(a, Left[Node] = NewNode(), L, Mid);
        Build(a, Right[Node] = NewNode(), Mid + 1, R);

        Merge(Node);
    }

    public : int Update(int i, type x)
    {
        Roots.push_back(Update(i, x, Roots.back(), 0, n - 1));
        return (int) Roots.size() - 1;
    }

    private : int Update(int i, type x, int Node, int L, int R)
    {
        if(i < L || R < i)  return Node;

        Node = NewNode(Node);

        if(i <= L && R <= i)    return Tree[Node] += x, Node;   /// Check this

        if(i <= Mid)    Left[Node] = Update(i, x, Left[Node], L, Mid);
        else            Right[Node] = Update(i, x, Right[Node], Mid + 1, R);

        return Merge(Node), Node;
    }

    public : type Query(int Version, int L, int R)
    {
        return Query(L, R, Roots[Version], 0, n - 1);
    }

    private : type Query(int i, int j, int Node, int L, int R)
    {
        if(i > j || L > R)  return E;
        if(j < L || R < i)  return E;

        if(i <= L && R <= j)    return Tree[Node];

        return Unite(Query(i, j, Left[Node], L, Mid), Query(i, j, Right[Node], Mid + 1, R));
    }

    public : void Clear()
    {
        n = 0;
        Counter = 0;
        Roots.clear();
    }
} myNonLazyTree;

int main()
{
    int n;  cin >> n;

    vector <int> a(n);
    for(int& x : a) scanf("%d", &x), x--;

    vector <int> Version(n);
    myNonLazyTree.Build(vector <int> (n, 0));

    for(int i = 0; i < n; i++)
    {
        static vector <int> Last(n, -1);

        if(Last[a[i]] + 1)  myNonLazyTree.Update(Last[a[i]], -1);

        Last[a[i]] = 1;
        Version[i] = myNonLazyTree.Update(i, +1);
    }

    for(int k = 1; k <= n; k++)
    {
        int i = n - 1;

        int Ans = 0;

        while(i >= 0)
        {
            int j = i;
            int Low = 0, High = i;

            while(Low <= High)
            {
                int MID = Low + (High - Low) / 2;

                if(myNonLazyTree.Query(Version[i], MID, i) <= k)    j = MID, High = MID - 1;
                else                                                Low = MID + 1;
            }

            Ans++;
            i = j - 1;
        }

        printf("%d ", Ans);
    }

    puts("");
}


#include <bits/stdc++.h>

using namespace std;

struct PersistentNonLazySegmentTree
{
    #define type int
    #define Mid ((L + R) >> 1)

    private : const type E = 0;     /// identity element    /// Check this
    private : static const int Nax = 100 * 100100;          /// Check this

    private : int n;        /// Array length
    private : int Counter;  /// Counter for nodes

    private : int Left[Nax];
    private : int Right[Nax];
    private : type Tree[Nax];
    private : vector <int> Roots;

    private : int NewNode()
    {
        Tree[Counter] = E;
        Left[Counter] = -1;
        Right[Counter] = -1;

        return Counter++;
    }

    private : int NewNode(int Copy)
    {
        Tree[Counter] = Tree[Copy];
        Left[Counter] = Left[Copy];
        Right[Counter] = Right[Copy];

        return Counter++;
    }

    private : type Unite(type x, type y)    /// Check this
    {
        return x + y;
    }

    private : void Merge(int Node)
    {
        Tree[Node] = Unite(Tree[Left[Node]], Tree[Right[Node]]);
    }

    public : int Build(const vector <type>& a)
    {
        Clear();
        n = a.size();
        Roots.push_back(NewNode());
        Build(a, Roots[0], 0, n - 1);
        return (int) Roots.size() - 1;
    }

    private : void Build(const vector <type>& a, int Node, int L, int R)
    {
        if(L == R)  return void(Tree[Node] = a[L]);

        Build(a, Left[Node] = NewNode(), L, Mid);
        Build(a, Right[Node] = NewNode(), Mid + 1, R);

        Merge(Node);
    }

    public : int Update(int i, type x)
    {
        Roots.push_back(Update(i, x, Roots.back(), 0, n - 1));
        return (int) Roots.size() - 1;
    }

    private : int Update(int i, type x, int Node, int L, int R)
    {
        if(i < L || R < i)  return Node;

        Node = NewNode(Node);

        if(i <= L && R <= i)    return Tree[Node] += x, Node;   /// Check this

        if(i <= Mid)    Left[Node] = Update(i, x, Left[Node], L, Mid);
        else            Right[Node] = Update(i, x, Right[Node], Mid + 1, R);

        return Merge(Node), Node;
    }

    public : int Query(int Version, int j, int k)
    {
        return Query(j, k, Roots[Version], 0, n - 1);
    }

    private : int Query(int j, int& k, int Node, int L, int R)
    {
        if(k < 0)   return j + 1;
        if(j < L)   return j + 1;
        if(L == R)  return k -= Tree[Node], k < 0 ? j + 1 : L;

        if(R <= j && k >= Tree[Node])
            return k -= Tree[Node], L;

        int x = Query(j, k, Right[Node], Mid + 1, R);
        int y = Query(j, k, Left[Node], L, Mid);

        return min(x, y);
    }

    public : void Clear()
    {
        n = 0;
        Counter = 0;
        Roots.clear();
    }
} myNonLazyTree;

int main()
{
    int n;  cin >> n;

    vector <int> a(n);
    for(int& x : a) scanf("%d", &x), x--;

    vector <int> Version(n);
    myNonLazyTree.Build(vector <int> (n, 0));

    for(int i = 0; i < n; i++)
    {
        static vector <int> Last(n, -1);

        if(Last[a[i]] + 1)  myNonLazyTree.Update(Last[a[i]], -1);

        Last[a[i]] = i;
        Version[i] = myNonLazyTree.Update(i, +1);
    }

    for(int k = 1; k <= n; k++)
    {
        int Ans = 0;

        for(int i = n - 1; i >= 0; i = myNonLazyTree.Query(Version[i], i, k) - 1)   Ans++;

        printf("%d ", Ans);
    }

    puts("");
}


#include <bits/stdc++.h>

using namespace std;

struct PersistentNonLazySegmentTree
{
    #define type int
    #define Mid ((L + R) >> 1)

    private : const type E = 0;     /// identity element    /// Check this
    private : static const int Nax = 100 * 100100;          /// Check this

    private : int n;        /// Array length
    private : int Counter;  /// Counter for nodes

    private : int Left[Nax];
    private : int Right[Nax];
    private : type Tree[Nax];
    private : vector <int> Roots;

    private : int NewNode()
    {
        Tree[Counter] = E;
        Left[Counter] = -1;
        Right[Counter] = -1;

        return Counter++;
    }

    private : int NewNode(int Copy)
    {
        Tree[Counter] = Tree[Copy];
        Left[Counter] = Left[Copy];
        Right[Counter] = Right[Copy];

        return Counter++;
    }

    private : type Unite(type x, type y)    /// Check this
    {
        return x + y;
    }

    private : void Merge(int Node)
    {
        Tree[Node] = Unite(Tree[Left[Node]], Tree[Right[Node]]);
    }

    public : int Build(const vector <type>& a)
    {
        Clear();
        n = a.size();
        Roots.push_back(NewNode());
        Build(a, Roots[0], 0, n - 1);
        return (int) Roots.size() - 1;
    }

    private : void Build(const vector <type>& a, int Node, int L, int R)
    {
        if(L == R)  return void(Tree[Node] = a[L]);

        Build(a, Left[Node] = NewNode(), L, Mid);
        Build(a, Right[Node] = NewNode(), Mid + 1, R);

        Merge(Node);
    }

    public : int Update(int i, type x)
    {
        Roots.push_back(Update(i, x, Roots.back(), 0, n - 1));
        return (int) Roots.size() - 1;
    }

    private : int Update(int i, type x, int Node, int L, int R)
    {
        if(i < L || R < i)  return Node;

        Node = NewNode(Node);

        if(i <= L && R <= i)    return Tree[Node] += x, Node;   /// Check this

        if(i <= Mid)    Left[Node] = Update(i, x, Left[Node], L, Mid);
        else            Right[Node] = Update(i, x, Right[Node], Mid + 1, R);

        return Merge(Node), Node;
    }

    public : type Query(int Version, int L, int R)
    {
        return Query(L, R, Roots[Version], 0, n - 1);
    }

    private : type Query(int i, int j, int Node, int L, int R)
    {
        if(i > j || L > R)  return E;
        if(j < L || R < i)  return E;

        if(i <= L && R <= j)    return Tree[Node];

        return Unite(Query(i, j, Left[Node], L, Mid), Query(i, j, Right[Node], Mid + 1, R));
    }

    public : void Clear()
    {
        n = 0;
        Counter = 0;
        Roots.clear();
    }
} myNonLazyTree;

int main()
{
    int n;  cin >> n;

    vector <int> a(n);
    for(int& x : a) scanf("%d", &x), x--;

    vector <int> Version(n);
    myNonLazyTree.Build(vector <int> (n, 0));

    for(int i = 0; i < n; i++)
    {
        static vector <int> Last(n, -1);

        if(Last[a[i]] + 1)  myNonLazyTree.Update(Last[a[i]], -1);

        Last[a[i]] = i;
        Version[i] = myNonLazyTree.Update(i, +1);
    }

    for(int k = 1; k <= n; k++)
    {
        int i = n - 1;

        int Ans = 0;

        while(i >= 0)
        {
            int j = i;
            int Low = 0, High = i;

            while(Low <= High)
            {
                int MID = Low + (High - Low) / 2;

                if(myNonLazyTree.Query(Version[i], MID, i) <= k)    j = MID, High = MID - 1;
                else                                                Low = MID + 1;
            }

            Ans++;
            i = j - 1;
        }

        printf("%d ", Ans);
    }

    puts("");
}