【Kickstart】2018 Round G - Combining Classes

解法

C++的整数长度真是令人头秃
解法本身不难,假如我们有个大小为 1 0 9 10^9 109的数组,Line Sweep遍历每个下标的时候可以得到该下标的点的个数
但是数组太大了,只能采取离散化的思想,用map记录坐标轴
每个R+1,表示多一个新区间,每个L-1-1,表示离开一个区间
最后从后往前遍历map,遍历到i的时候累加的前缀和grp(还没加上map[i]时的值)表示的是(i,i->next]之间有多少组并行,即在这个区间内,每个都会出现grp
如果要求这个区间里第k个(从0开始),那么它的数字应该对应的是i->next-k/grp

#include <stdio.h>
#include <string>
#include <iostream>
#include <memory.h>
#include <stdlib.h>
#include <cmath>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <algorithm>
#include <functional>

#define MAXN 400010
#define MAXQ 100010
#define ZERO 10e-6


using namespace std;

typedef long long lld;

int n,q;
int X[MAXN],Y[MAXN],Z[MAXQ];
int L[MAXN],R[MAXN];
pair<int,int> K[MAXQ];
lld A[3],B[3],C[3],M[3];
map<int,int> axis;



int main() {
//    freopen("/Users/huangyuemei/CLionProjects/untitled/B-small-practice.in","r",stdin);
//    freopen("/Users/huangyuemei/CLionProjects/untitled/my.out","w",stdout);
    int t;
    scanf("%d",&t);
    for(auto round=1;round<=t;++round) {
        scanf("%d%d",&n,&q);
        scanf("%d%d%d%d%d%d",&X[0],&X[1],&A[0],&B[0],&C[0],&M[0]);
        scanf("%d%d%d%d%d%d",&Y[0],&Y[1],&A[1],&B[1],&C[1],&M[1]);
        scanf("%d%d%d%d%d%d",&Z[0],&Z[1],&A[2],&B[2],&C[2],&M[2]);
        for(int i=2;i<n;i++) {
            X[i] = ((lld)A[0]*X[i-1]+(lld)B[0]*X[i-2]+C[0])%M[0];
            Y[i] = ((lld)A[1]*Y[i-1]+(lld)B[1]*Y[i-2]+C[1])%M[1];
        }
        for(int i=2;i<q;++i) {
            Z[i] = ((lld)A[2]*Z[i-1]+(lld)B[2]*Z[i-2]+C[2])%M[2];
        }
        axis.clear();
//        int all = 0;
        for(int i=0;i<n;++i) {
            L[i] = min(X[i],Y[i]);
            R[i] = max(X[i],Y[i])+1;
            axis[L[i]] -= 1;
            axis[R[i]] += 1;
//            all += R[i]-L[i];
        }
        for(int i=0;i<q;++i) {
            K[i].first = Z[i];
            K[i].second = i+1;
        }
        sort(K,K+q);
        int ptr = 0, grps = 0, prev = 0;
        lld total = 0;
        lld ans = 0;
        for(auto it = axis.end();it!=axis.begin();) {
            it--;
            lld interL = (lld)(prev-it->first)*grps;
            while(ptr<q && K[ptr].first-total<interL) {
                ans += (lld)(prev-(K[ptr].first-total)/grps)*K[ptr].second;
                ptr++;
            }
            if(ptr==q) break;
            prev = it->first;
            grps += it->second;
            total += interL;
        }
//        printf("%lld\n",all);
        printf("Case #%d: %lld\n",round,ans);
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值