http://acm.hdu.edu.cn/showproblem.php?pid=3581
题意:
数轴上给出n条线段,m个点,问任意两对点构成的线段被多少条线段包含
枚举给出的线段[x,y]
枚举被包含线段起点[第一个>=x的点,最后一个<=y的点]
被包含线段终点是最后一个<=y的点
差分前缀和即可
还有一种解法是
将给出的线段按左端点从小到大排序
从小到大考虑每一个点
把左端点<=该点的线段拿出来,按右端点从小到大排序
从小到大考虑该点后面的某个点
把右端点<=该点后面某个点的线段拿走
剩下的线段个数就是该点和后面某个点组成的线段被多少线段包含
因为若线段包含由第i个点和第j个点组成的线段,那么它必定包含由第i+1个点和第j个点组成的线段
所以每次只考虑左端点在第i个点后面,在第i+1个点前面的即可
#include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 100001 #define M 502 int l[N],r[N],pos[M]; int sum[M][M]; int main() { int T,n,m,x,y; scanf("%d",&T); for(int t=1;t<=T;++t) { scanf("%d%d",&n,&m); for(int i=1;i<=n;++i) scanf("%d%d",&l[i],&r[i]); for(int i=1;i<=m;++i) scanf("%d",&pos[i]); for(int i=1;i<=n;++i) { x=lower_bound(pos+1,pos+m+1,l[i])-pos; y=upper_bound(pos+1,pos+m+1,r[i])-pos-1; for(int j=x;j<=y;++j) { sum[j][j]++; sum[j][y+1]--; } } for(int i=1;i<=m;++i) for(int j=1;j<=m;++j) sum[i][j]+=sum[i][j-1]; for(int i=1;i<=m;++i) for(int j=i+1;j<=m;++j) sum[j][i]=sum[i][j]; printf("Case %d: ",t); for(int i=1;i<=m;++i) { for(int j=1;j<m;++j) printf("%d ",sum[i][j]); printf("%d ",sum[i][m]); } printf(" "); memset(sum,0,sizeof(sum)); memset(pos,0,sizeof(pos)); } return 0; }