E - BaoBao Loves Reading ( 莫队+奇偶优化 )
题目链接:https://vjudge.net/problem/ZOJ-4117
题意:现在有一个书架和一个书桌,书架上有 n 本书,书桌有容量,不能放超过容量的书,现在需要按照顺序读书,给出一个读书的顺序,要求给出书桌容量对应 1-n 的情况下,最少要拿多少次书。
思路:我们单独考虑每一种书的情况,假如序列a={4,3,4,2,3,1,4} , 我们只考虑4这本书, 我们发现如果两个相邻的4中间有3个不同数,那么当书桌容量小于等于3时贡献答案1 .
这就转变成了求区间不同数的个数。
这题应该卡了普通莫队,网上解析全部用的树状数组。
但我加了个快读和奇偶优化就跑过了。
代码:
#include <bits/stdc++.h>
using namespace std;
vector<int> G[200005];
int ans[200005],via[200005],a[200005];
int n,m,block,l,r,now;
struct node {
int l,r,bl;
}q[200005];
inline int read(){
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
int rule( node a, node b )
{
return (a.bl)^(b.bl)?a.l<b.l:(((a.bl)&1)?a.r<b.r:a.r>b.r);
}
void add( int x ) // 加入操作
{
if ( via[a[x]]==0 ) now++;
via[a[x]]++;
}
void del( int x ) // 删除操作
{
via[a[x]]--;
if ( via[a[x]]==0 ) {
now --;
}
}
signed main()
{
int T;cin>>T;
while ( T-- ) {
cin >> n;
for ( int i=0; i<=n; i++ ) {
G[i].clear();
ans[i] = 0;
via[i] = 0;
}
for ( int i=1; i<=n; i++ ) {
a[i] = read();
G[a[i]].push_back(i);
}
m=0;
for ( int i=1; i<=n; i++ ) {
if ( G[i].size()==0 ) continue;
else if ( G[i].size()==1 ) ans[n]++;
else {
ans[n]++;
for ( int j=0; j<G[i].size()-1; j++ ) {
q[m].l = G[i][j]+1;
q[m].r = G[i][j+1]-1;
q[m].bl=((q[m].l-1)/sqrt(n)/2)+1;
if ( q[m].l<=q[m].r ) m ++;
}
}
}
block = sqrt(m/3);
if ( block>0 ) sort(q,q+m,rule);
l = 1; r = 0; now=0;
for ( int i=0; i<m; i++ ) {
while ( l<q[i].l ) {
del(l++);
}
while ( l>q[i].l ) {
add(--l);
}
while ( r<q[i].r ) {
add(++r);
}
while ( r>q[i].r ) {
del(r--);
}
ans[now] ++;
}
for ( int i=n-1; i>=1; i-- ) {
ans[i] += ans[i+1];
}
for ( int i=1; i<n; i++ ) printf("%d ",ans[i]);
printf("%d\n",ans[n]);
}
return 0;
}