結果

問題 No.2761 Substitute and Search
ユーザー naut3
提出日時 2024-05-17 22:58:47
言語 Rust
(1.83.0 + proconio)
結果
AC  
実行時間 3,420 ms / 4,000 ms
コード長 5,011 bytes
コンパイル時間 13,816 ms
コンパイル使用メモリ 401,776 KB
実行使用メモリ 102,572 KB
最終ジャッジ日時 2024-12-20 14:59:59
合計ジャッジ時間 38,533 ms
ジャッジサーバーID
(参考情報)
judge3 / judge1
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 3
other AC * 13
権限があれば一括ダウンロードができます
コンパイルメッセージ
warning: unused variable: `L`
 --> src/main.rs:7:19
  |
7 |         N: usize, L: usize, Q: usize,
  |                   ^ help: if this is intentional, prefix it with an underscore: `_L`
  |
  = note: `#[warn(unused_variables)]` on by default

ソースコード

diff #
プレゼンテーションモードにする

#![allow(non_snake_case, unused_imports)]
use proconio::{fastout, input, marker::*};
#[fastout]
fn main() {
input! {
N: usize, L: usize, Q: usize,
mut S: [Chars; N],
}
let mut rhs = vec![];
for i in 0..N {
let rh = UpdateableRollingHash::from(&S[i]);
rhs.push(rh);
}
for _ in 0..Q {
input! {
t: usize
}
if t == 1 {
input! {
k: Usize1, c: char, d: char,
}
for i in 0..N {
if S[i][k] == c {
S[i][k] = d;
rhs[i].update(k, d);
}
}
} else {
input! {
t: Chars,
}
let l = t.len();
let rh = UpdateableRollingHash::from(&t);
let h = rh.hash(0..l);
let mut ans = 0usize;
for i in 0..N {
let hi = rhs[i].hash(0..l);
if hi == h {
ans += 1;
}
}
println!("{}", ans);
}
}
}
pub struct UpdateableRollingHash {
length: usize,
tree: Vec<u64>,
pow: Vec<u64>,
}
impl UpdateableRollingHash {
const MOD: u64 = (1_u64 << 61) - 1;
const MASK_30: u64 = (1_u64 << 30) - 1;
const MASK_31: u64 = (1_u64 << 31) - 1;
const MASK_61: u64 = (1_u64 << 61) - 1;
const BASE: u64 = 100;
const STR_BASE: char = 'a';
fn inv(x: u64) -> u64 {
return Self::pow(x, Self::MOD - 2);
}
fn pow(mut a: u64, mut b: u64) -> u64 {
let mut ret = 1;
while b > 0 {
if b & 1 == 1 {
ret = Self::cmod(Self::mul(ret, a));
}
a = Self::cmod(Self::mul(a, a));
b >>= 1;
}
return ret;
}
fn mul(a: u64, b: u64) -> u64 {
let au = a >> 31;
let ad = a & Self::MASK_31;
let bu = b >> 31;
let bd = b & Self::MASK_31;
let mid = ad * bu + au * bd;
let midu = mid >> 30;
let midd = mid & Self::MASK_30;
return Self::cmod(au * bu * 2 + midu + (midd << 31) + ad * bd);
}
fn cmod(x: u64) -> u64 {
let xu = x >> 61;
let xd = x & Self::MASK_61;
let ret = xu + xd;
if ret >= Self::MOD {
return ret - Self::MOD;
} else {
return ret;
}
}
/// Prepare to calc given string s's substring hash value
pub fn from(s: &[char]) -> Self {
let length = s.len();
let mut tree = vec![0; 2 * length];
let mut pow = vec![1];
for i in 0..length {
pow.push(Self::cmod(Self::mul(pow[i], Self::BASE)));
}
for i in 0..length {
tree[i + length] = Self::cmod(Self::mul(
s[i] as u64 + 1 - Self::STR_BASE as u64,
pow[length - i - 1],
));
}
for i in (1..length).rev() {
tree[i] = Self::cmod(tree[i << 1] + tree[(i << 1) | 1]);
}
return Self {
length: length,
tree: tree,
pow: pow,
};
}
/// Update p-th character to 'c'
pub fn update(&mut self, mut p: usize, c: char) {
let v = Self::cmod(Self::mul(
c as u64 + 1 - Self::STR_BASE as u64,
self.pow[self.length - p - 1],
));
p += self.length;
self.tree[p] = v;
while p > 1 {
p >>= 1;
self.tree[p] = Self::cmod(self.tree[p << 1] + self.tree[(p << 1) | 1]);
}
}
fn _get_sum(&self, left: usize, right: usize) -> u64 {
let (mut l, mut r) = (left + self.length, right + self.length);
let (mut vl, mut vr) = (0, 0);
while l < r {
if l & 1 == 1 {
vl = Self::cmod(vl + self.tree[l]);
l += 1;
}
if r & 1 == 1 {
r -= 1;
vr = Self::cmod(self.tree[r] + vr);
}
l >>= 1;
r >>= 1;
}
return Self::cmod(vl + vr);
}
fn _hash(&self, left: usize, right: usize) -> u64 {
let lv = self._get_sum(0, left);
let rv = self._get_sum(0, right);
return Self::cmod(Self::mul(
rv + Self::MOD * 4 - lv,
Self::inv(self.pow[self.length - right + 1]),
));
}
/// Calculate hash value of s[range]
pub fn hash<R: std::ops::RangeBounds<usize>>(&self, range: R) -> u64 {
let left = match range.start_bound() {
std::ops::Bound::Included(&l) => l,
std::ops::Bound::Excluded(&l) => l + 1,
std::ops::Bound::Unbounded => 0,
};
let right = match range.end_bound() {
std::ops::Bound::Included(&r) => r + 1,
std::ops::Bound::Excluded(&r) => r,
std::ops::Bound::Unbounded => self.length - 1,
};
return self._hash(left, right);
}
}
הההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההההה
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
0