题目链接:点击打开链接
题目大意:n种纪念品能在第l个车站到第r个车站能买到,一共有m个车站,问你一次分别隔1个,2个……m个车站分别能买到几种纪念品
题目思路:刚开始还以为直接暴力就好,结果第七个样例就凉了,结束以后看了学长代码没看懂,问了学长好久,想了两个小时才搞懂..太菜了,回归正题。
这道题是用vector把区间长度相同的车站序号放在一起(非常机智的做法),然后开始从1到m也就是车站间隔进行求解,如果纪念品能买的车站区间比车站间隔要大,那很明显这种纪念品肯定可以被买,也就是后面的n。然后如果有跟车站间隔相同的车站区间纪念品,那就把能买到这种纪念品的地方都+1,然后从i开始每次跳i把数字加起来就行了,因为车站间隔和纪念品车站区间相同,所以这么跳的话,肯定每个地方加的数字对应的纪念品都是独一无二的纪念品。
以下是代码:
#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define MAXN 300005
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
int n,m,sum[MAXN];
struct node{
int l,r;
}a[MAXN];
vector<int>v[MAXN];
int lowbit(int x){
return x&-x;
}
void add(int x,int y){
while(x<=m){
sum[x]+=y;
x+=lowbit(x);
}
}
int query(int x){
int ans=0;
while(x){
ans+=sum[x];
x-=lowbit(x);
}
return ans;
}
int main(){
while(~scanf("%d%d",&n,&m)){
memset(sum,0,sizeof(sum));
rep(i,1,m){
v[i].clear();
}
rep(i,1,n){
scanf("%d%d",&a[i].l,&a[i].r);
int temp=a[i].r-a[i].l+1;
v[temp].push_back(i);
}
rep(i,1,m){
int ans=0,len=v[i].size();
rep(j,0,len-1){
int pos=v[i][j];
add(a[pos].l,1);
add(a[pos].r+1,-1);
}
for(int j=i;j<=m;j+=i){
ans+=query(j);
}
n-=len;
printf("%d\n",ans+n);
}
}
return 0;
}