题意:
给你n*k个数a,每个数的值都在[1,n]之间,且每种值正好有k个,让你输出n个区间,
1.第i个区间
x
i
,
y
i
x_i,y_i
xi,yi要满足
a
[
x
i
]
=
a
[
y
i
]
=
i
a[x_i]=a[y_i]=i
a[xi]=a[yi]=i。
2.且对于数组里面所有的数,它最多只能被包含在
⌈
n
k
−
1
⌉
⌈\frac{n}{k−1}⌉
⌈k−1n⌉个区间里。
题解:
其实平时做到这种题目就是连蒙带猜写的…感觉上答案对了且暂时找不到反例就写写试试。但是写博客还是得稍微地证明一下。
一般这种题目都是贪心地从前往后做,那我想到的就是先把所有满足条件1的区间按右端点从小到大排序。然后贪心地找值未出现过的右端点最小的区间,并且还要看这个区间是否满足第二个条件。那么我就用线段树来维护区间和和区间最大值,然后查找最右端的不能再被覆盖的点。
那么证明题解里面有写,就是如果按照这样子做某个值x是取不到的,那么任意两个x之间一定是被
⌈
n
k
−
1
⌉
⌈\frac{n}{k−1}⌉
⌈k−1n⌉个不同的值覆盖了,然后总共除了x会有k-1个不同的值。也就是总长度至少为(k-1)*
⌈
n
k
−
1
⌉
⌈\frac{n}{k−1}⌉
⌈k−1n⌉>=n,那么是不可能存在的。
C++代码:
#include<bits/stdc++.h>
using namespace std;
const int N=105;
int a[N*N],n,k,mx[N*N*4],f[N*N*4],val;
void push_down(int root){
if(!f[root])return ;
mx[root<<1]+=f[root];
mx[root<<1|1]+=f[root];
f[root<<1]+=f[root];
f[root<<1|1]+=f[root];
f[root]=0;
}
void update(int l,int r,int root,int ql,int qr){
if(l>=ql&&r<=qr){
mx[root]++;
f[root]++;
return ;
}
push_down(root);
int mid=l+r>>1;
if(mid>=ql)
update(l,mid,root<<1,ql,qr);
if(mid<qr)
update(mid+1,r,root<<1|1,ql,qr);
mx[root]=max(mx[root<<1],mx[root<<1|1]);
}
int query(int l,int r,int root){
if(mx[root]<val)return -1;
if(l==r)return l;
int mid=l+r>>1;
push_down(root);
if(mx[root<<1|1]>=val)return query(mid+1,r,root<<1|1);
return query(l,mid,root<<1);
}
int vis[N];
struct node{
int l,r;
bool operator< (const node& aa)const {
return r<aa.r;
}
}e[N*N];
int ans[N][2];
int main()
{
scanf("%d%d",&n,&k);
val=(n+k-1-1)/(k-1);
int lef=1,res=n,all=0;
for(int i=1;i<=n*k;i++){
scanf("%d",&a[i]);
if(vis[a[i]])e[++all]={vis[a[i]],i};
vis[a[i]]=i;
}
sort(e+1,e+1+all);
int rig=-1;
for(int i=1;i<=all;i++){
rig=query(1,n*k,1);
if(e[i].r<=rig||e[i].l<=rig||ans[a[e[i].l]][0])continue;
ans[a[e[i].l]][0]=e[i].l,ans[a[e[i].l]][1]=e[i].r;
update(1,n*k,1,e[i].l,e[i].r);
}
for(int i=1;i<=n;i++)
printf("%d %d\n",ans[i][0],ans[i][1]);
return 0;
}
Python代码:
a=[0]*10005;mx=[0]*40005;f=[0]*40005
val=0
def push_down(root):
if f[root]==0:return
mx[root<<1]+=f[root]
mx[root<<1|1]+=f[root]
f[root<<1]+=f[root]
f[root<<1|1]+=f[root]
f[root]=0
def update(l,r,root,ql,qr):
if l>=ql and r<=qr:
mx[root]+=1
f[root]+=1
return
push_down(root)
mid=l+r>>1
if mid>=ql:
update(l,mid,root<<1,ql,qr)
if mid<qr:
update(mid+1,r,root<<1|1,ql,qr)
mx[root]=max(mx[root<<1],mx[root<<1|1])
def query(l,r,root):
if mx[root]<val:return -1
if l==r:return l
mid=l+r>>1
push_down(root)
if mx[root<<1|1]>=val :
return query(mid+1,r,root<<1|1)
return query(l,mid,root<<1)
vis=[0]*10005
ans=[[0]*2 for i in range(10005)]
n,k=map(int,input().split(' '))
val=(n+k-1-1)//(k-1)
lef=1;res=n
a=[0]
a+=list(map(int,input().split(' ')))
e=[]
for i in range(1,n*k+1):
if vis[a[i]]!=0:
e.append([vis[a[i]],i])
vis[a[i]]=i
def cmp(x):
return x[1]
e.sort(key=cmp)
rig=-1
all=len(e)
for i in range(all):
rig=query(1,n*k,1)
if e[i][1]<=rig or e[i][0]<=rig or ans[a[e[i][0]]][0]!=0:continue
ans[a[e[i][0]]][0]=e[i][0];ans[a[e[i][0]]][1]=e[i][1]
update(1,n*k,1,e[i][0],e[i][1])
for i in range(1,n+1):
print(ans[i][0],ans[i][1])