ARC068C - Snuke Line
Description
其实就是给出nnn个区间[li,ri][l_i,r_i][li,ri]对于每一个i∈[1,M]i\in[1,M]i∈[1,M],求:
∑j=1n[⌊rji⌋−⌊lj−1i⌋≥1]\sum_{j=1}^n[\lfloor \frac{r_j}{i}\rfloor-\lfloor \frac{l_j-1}{i}\rfloor\geq 1]j=1∑n[⌊irj⌋−⌊ilj−1⌋≥1]
好吧其实这样思考感觉更难了。。。
Solution
考虑计算这个的瓶颈,我们自然地想到用调和级数级别的方法去计算这类问题:对于每个位置ttt,求出st=∑jt∈[lj,rj]s_t=\sum_j{t\in[l_j,r_j]}st=∑jt∈[lj,rj],也就是ttt被包含的区间个数(这可以用树状数组维护),然后直接枚举iii的倍数计算答案。但这样会有问题,原因在于一个区间可能存在多个iii的倍数,产生重复贡献。
进一步的,我们发现当rj−lj+1>=ir_j-l_j+1>=irj−lj+1>=i时,必然为111,否则必然不大于111,有了这个性质,我们就可以只对长度小于iii的区间统计sis_isi,枚举iii的倍数计算,剩下的区间都会产生111的贡献,直接统计即可。
时间复杂度O(nlnMlgM+nlgn)O(n\;lnM\;lgM+nlgn)O(nlnMlgM+nlgn)。
Code
#include <vector>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cctype>
#include <string>
#include <cstring>
#include <ctime>
#include <cassert>
#include <string.h>
//#include <unordered_set>
//#include <unordered_map>
//#include <bits/stdc++.h>#define MP(A,B) make_pair(A,B)
#define PB(A) push_back(A)
#define SIZE(A) ((int)A.size())
#define LEN(A) ((int)A.length())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define fi first
#define se secondusing namespace std;template<typename T>inline bool upmin(T &x,T y) { return y<x?x=y,1:0; }
template<typename T>inline bool upmax(T &x,T y) { return x<y?x=y,1:0; }typedef long long ll;
typedef unsigned long long ull;
typedef long double lod;
typedef pair<int,int> PR;
typedef vector<int> VI;const lod eps=1e-11;
const lod pi=acos(-1);
const int oo=1<<30;
const ll loo=1ll<<62;
const int mods=998244353;
const int MAXN=300005;
const int INF=0x3f3f3f3f;//1061109567
/*--------------------------------------------------------------------*/
inline int read()
{int f=1,x=0; char c=getchar();while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }while (c>='0'&&c<='9') { x=(x<<3)+(x<<1)+(c^48); c=getchar(); }return x*f;
}
PR a[MAXN];
int s[MAXN],n,m;
void add(int x,int y) { for (;x<=m+1;x+=x&(-x)) s[x]+=y; }
int query(int x) { int ans=0; for (;x;x-=x&(-x)) ans+=s[x]; return ans; }
signed main()
{n=read(),m=read();for (int i=1;i<=n;i++) a[i].fi=read(),a[i].se=read();sort(a+1,a+n+1,[&](PR x,PR y){ return x.se-x.fi<y.se-y.fi; });for (int i=1,nw=1;i<=m;i++){while (nw<=n&&a[nw].se-a[nw].fi+1<i) add(a[nw].fi,1),add(a[nw].se+1,-1),nw++;int ans=n-nw+1;for (int j=i;j<=m;j+=i) ans+=query(j);printf("%d\n",ans);}return 0;
}