『Atcoder 068E』Snuke Line

题目链接戳这里!!

原题链接戳这个


問題文

すぬけくんは鉄道会社を運営するゲームで遊ぶことにしました。すぬけ鉄道には M+1 個の駅があり、 0 から M までの番号がついています。 すぬけ鉄道の列車は駅 0 から d 駅ごとに停車します。 例えば d=3 のとき駅 0,駅 3,駅 6,駅 9, … に停車します。

すぬけ鉄道が走っている地域には N 種類の名産品があり、種類 i の名産品は 駅 li,駅 li+1,駅 li+2, …, 駅 ri のいずれかに列車が停車したとき購入することが可能です。

列車が停車する間隔 d は 1,2,3,…,MM 種類が存在しています。 M 種類の列車それぞれについて、その列車に駅 0 で乗車した場合に購入可能な名産品の種類数を求めなさい。 なお、列車から別の列車への乗り換えは許されないものとします。


中文翻译

有m+1个车站0~m,有n种商品,第i种只在[li,ri]出售,编号为i的列车只会在i的倍数的站停车,求对于编号1-m的列车,你能在站台上买到几种商品。



解题思路

暴力枚举很容易想到,但是肯定T。

因为每个商品都可以在一个区间内得到,所以我们可以想到,对于每个区间都加上1,那么每个点的值就是答案。

但是这样有问题,有可能一种商品被选了多次。

对于每个大于等于d的区间,其中一定有一个数\(mod \ d\)答案为0,而我们前面所想到的正是这种问题,这样,我们从小到大枚举i,那么显然区间长度大于等于i的一定能被选到,我们可以直接在答案中加上。小于d的区间,我们可以使用线段树或者树状数组维护,每次计算完i的答案后,将长度为i的区间进行维护。

手贱,写的线段树。


顺便吐槽一句评测的数据有锅 @C_K_Y_



代码

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
using namespace std;
const int maxn=300050;
int sum[maxn<<3],lazy[maxn<<3],l[maxn],r[maxn];
int n,M;
vector<int>q[maxn];
inline void push_down(int ID,int l,int r){
    int m=(l+r)>>1;
    sum[ID<<1]+=(m-l+1)*lazy[ID],sum[ID<<1|1]+=(r-m)*lazy[ID];
    lazy[ID<<1]+=lazy[ID],lazy[ID<<1|1]+=lazy[ID],lazy[ID]=0;
}
inline void ins(int ID,int l,int r,int L,int R){
    if(lazy[ID])push_down(ID,l,r);
    if(l>=L&&r<=R){
        sum[ID]+=(r-l+1);
        lazy[ID]++;
        return;
    }
    int m=(l+r)>>1;
    if(m>=L)ins(ID<<1,l,m,L,R);
    if(m<R)ins(ID<<1|1,m+1,r,L,R);
    sum[ID]=sum[ID<<1]+sum[ID<<1|1];
}
inline int query(int ID,int x,int l,int r){
    if(lazy[ID])push_down(ID,l,r);
    if(sum[ID]==0)return 0;
    if(l==r)return sum[ID];
    int m=(l+r)>>1;
    if(m>=x)return query(ID<<1,x,l,m);
    else return query(ID<<1|1,x,m+1,r);
}
int main(){
    scanf("%d%d",&n,&M);
    for(register int i=1;i<=n;i++){
        scanf("%d%d",&l[i],&r[i]);
        q[r[i]-l[i]+1].push_back(i);
    }
    int remain=n;
    for(register int i=1;i<=M;i++){
        int ans=remain;
        remain-=q[i].size();
        if(i!=1)
        for(register int j=1;j*i<=M;j++)ans+=query(1,i*j,1,300000);
        for(register int j=0;j<q[i].size();j++)ins(1,1,300000,l[q[i][j]],r[q[i][j]]);
        printf("%d\n",ans);
    }
}

猜你喜欢

转载自www.cnblogs.com/Fang-Hao/p/9544677.html
今日推荐