列表

详情


ZJ19. 万万没想到之抓捕孔连顺

描述

我叫王大锤,是一名特工。我刚刚接到任务:在字节跳动大街进行埋伏,抓捕恐怖分子孔连顺。和我一起行动的还有另外两名特工,我提议

1. 我们在字节跳动大街的 N 个建筑中选定 3 个埋伏地点。
2. 为了相互照应,我们决定相距最远的两名特工间的距离不超过 D 。

我特喵是个天才! 经过精密的计算,我们从X种可行的埋伏方案中选择了一种。这个方案万无一失,颤抖吧,孔连顺!
……
万万没想到,计划还是失败了,孔连顺化妆成小龙女,混在cosplay的队伍中逃出了字节跳动大街。只怪他的伪装太成功了,就是杨过本人来了也发现不了的!

请听题:给定 N(可选作为埋伏点的建筑物数)、 D(相距最远的两名特工间的距离的最大值)以及可选建筑的坐标,计算在这次行动中,大锤的小队有多少种埋伏选择。
注意:
1. 两个特工不能埋伏在同一地点
2. 三个特工是等价的:即同样的位置组合( A , B , C ) 只算一种埋伏方法,不能因“特工之间互换位置”而重复使用


数据范围:

输入描述

第一行包含空格分隔的两个数字 N和D(1 ≤ N ≤ 1000000; 1 ≤ D ≤ 1000000)

第二行包含N个建筑物的的位置,每个位置用一个整数(取值区间为[0, 1000000])表示,从小到大排列(将字节跳动大街看做一条数轴)

输出描述

一个数字,表示不同埋伏方案的数量。结果可能溢出,请对 99997867 取模

示例1

输入:

4 3
1 2 3 4

输出:

4

说明:

可选方案 (1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)

示例2

输入:

5 19
1 10 20 30 50

输出:

1

说明:

可选方案 (1, 10, 20)

示例3

输入:

2 100
1 102

输出:

0

说明:

无可选方案

原站题解

Rust 解法, 执行用时: 8ms, 内存消耗: 2436KB, 提交时间: 2022-05-16

use std::io::BufRead;
pub struct Scanner<B> {
    reader: B,
    buf_str: Vec<u8>,
    buf_iter: std::str::SplitWhitespace<'static>,
}
 
impl<B: BufRead> Scanner<B> {
    pub fn new(reader: B) -> Self {
        Self {
            reader,
            buf_str: Vec::new(),
            buf_iter: "".split_whitespace(),
        }
    }
    pub fn token<T: std::str::FromStr>(&mut self) -> T {
        loop {
            if let Some(token) = self.buf_iter.next() {
                return token.parse().ok().expect("Failed parse");
            }
            self.buf_str.clear();
            self.reader
                .read_until(b'\n', &mut self.buf_str)
                .expect("Failed read");
            self.buf_iter = unsafe {
                let slice = std::str::from_utf8_unchecked(&self.buf_str);
                std::mem::transmute(slice.split_whitespace())
            }
        }
    }
}

fn main() {
    let stdin = std::io::stdin();
    let mut scanner = Scanner::new(stdin.lock());
    let n: usize = scanner.token();
    let d: usize = scanner.token();
    let mut r = 0;
    let mut v = vec![0; n];
    for i in &mut v {
        *i = scanner.token()
    }
    while v.len() > 3 && v[1] - v[0] > d {
        v.pop();
    }
    while v.len() > 3 && v[v.len()-1] - v[v.len()-2] > d {
        v.pop();
    }
    if v.len() < 3 {
        println!("-1");
        return
    }
    let mut left = 0; let mut right = 2;
    while right < v.len() {
        if v[right] - v[left] > d {
            left += 1
        } else if right - left < 2 {
            right += 1
        } else {
            let num = right - left;
            r += num * (num-1) / 2;
            right += 1
        }
    }
    r = r % 99997867;
    println!("{}", r)
}

C++ 解法, 执行用时: 10ms, 内存消耗: 1232KB, 提交时间: 2021-03-24

#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<vector>
#include<queue>
#include<stack>
#include<string>
#include<algorithm>
#include<map>
#include<set>
#define ll long long
#define ull unsigned long long
#define inf 0x3f3f3f3f
#define P pair<ll,ll>
const ll mod = 99997867;
const ll maxn = 60000;
using namespace std;
inline int read() {
    char c = getchar(); int x = 0, f = 1;
    while(!isdigit(c)) {if(c == '-') f = -1; c = getchar();}
    while(isdigit(c)) {x = x*10 + c - '0'; c = getchar();}
    return f * x;
}
int main(){
    int n = read(),d = read();
    queue<int> path;
    ll ans = 0;
    for(int i = 0; i < n; i++) {
        if(path.empty()) {path.push(read());continue;}
        int input = read();
        while(!path.empty() && path.front() + d < input) path.pop();
        if(path.size() >= 2) ans += path.size() * (path.size()-1) / 2;
        path.push(input);
        ans %= mod;
    }
    printf("%lld",ans);
}

上一题