BaoBao Loves Reading ZOJ - 4117 (思维/求区间不同种类数)
对于每个数,我们记录上一次这个数出现的位置;
计算之间间隔了几个不同数x,如果一个桌子的容量>=x,那我们不用把书放回,如果桌子的容量<x,那么我们只能把书放回去这本书
定义 t[] 每次使t[x]++,也就是对于容量小于 x的桌子每次都要从新取书,对于大于等于x的桌子不用
最后累加起来,最后结果就是
n-(t[1]+...+t[i]);
对于求区间不同种类的数字 可以用树状数组 莫队 主席树;
#include<bits/stdc++.h> using namespace std; const int maxn=2e5+10; const double EPS=1e-12; #define mem(a,b) memset(a,b,sizeof(a)) #define ll long long int tree[maxn]; int ans[maxn],pre[maxn]; int vis[maxn],arr[maxn]; int n; int lowbit(int x) { return x&(-x); } void add(int x,int val) { while(x<=n) { tree[x]+=val; x+=lowbit(x); } //cout<<"hereadd"<<endl; } int sum(int x) { int temp=0; while(x>0) { temp+=tree[x]; x-=lowbit(x); } //cout<<"heresum"<<endl; return temp; } void init() { mem(arr,0); mem(vis,0); mem(tree,0); mem(ans,0); mem(pre,0); } int main() { int t; cin>>t; while(t--) { init(); cin>>n; for(int i=1;i<=n;i++) { cin>>arr[i]; pre[i]=vis[arr[i]]; vis[arr[i]]=i; } //cout<<"here"<<endl; for(int i=1;i<=n;i++) { if(pre[i]) { add(pre[i],-1); add(i,1); int temp=sum(i)-sum(pre[i]-1); ans[temp]++; } else add(i,1); } //cout<<"here"<<endl; int tot=0; for(int i=1;i<=n;i++) { tot+=ans[i]; if(i!=1) cout<<" "; cout<<n-tot; } cout<<"\n"; } return 0; }