// clang-format off
#include<bits/stdc++.h>
using namespace std;
using ULL=unsigned long long;
#define FOR(i,l,r) for(auto i=(l);i<=(r);++i)
#define REP(i,n) FOR(i,0,(n)-1)
#define ssize(x) int(x.size())
auto operator<<(ostream&o,auto p)->decltype(p.first,o){return o<<"("<<p.first<<", "<<p.second<<")";}
auto operator<<(ostream&o,auto x)->decltype(x.end(),o){o<<"{";int i=0;for(auto e:x)o<<(", ")+2*!i++<<e;return o<<"}";}
#ifdef DEBUG
#define debug(x...) cerr<<"["#x"]: ",[](auto...$){((cerr<<$<<"; "),...);}(x),cerr<<'\n'
#else
#define debug(...) {}
#endif
// clang-format on
const int MOD = 1000000000 + 7;
// clang-format off
int add(const int &a, const int &b) { return a + b >= MOD ? a + b - MOD : a + b; }
int mul(const int &a, const int &b) { return 1LL * a * b % MOD; }
int sub(const int &a, const int &b) { return a >= b ? a - b : MOD + a - b; }
int fast_pow(int base, int exp);
int modinv(const int& x) { return fast_pow(x, MOD - 2); }
// clang-format on
struct Linear
{
int a = 1, b = 0;
static inline Linear compose(Linear f, Linear g) // apply f then g
{
return {mul(g.a, f.a), add(mul(g.a, f.b), g.b)};
}
inline Linear inverse()
{
auto ai = modinv(a);
return {.a = ai, .b = sub(0, mul(ai, b))};
}
};
struct Option
{
int add, mul;
inline bool always_add() const { return mul <= 1; }
inline Linear linear() const
{
return always_add() ? Linear{.a = 1, .b = add}
: Linear{.a = mul, .b = 0};
}
};
struct PrefSum
{
vector<Linear> pref;
PrefSum(const vector<Option> &ops)
: pref(ops.size() + 1)
{
REP (i, ssize(ops))
pref[i + 1] = Linear::compose(pref[i], ops[i].linear());
}
Linear query(int beg, int end)
{
return Linear::compose(pref[beg].inverse(), pref[end]);
}
};
int nops, nqueries;
vector<Option> ops; // (add, or mul)
vector<pair<int, Linear>> jp; // (pos, operations on the way to pos)
vector<int> next_mul;
vector<ULL> add_combo; // pref sum since last mul
void process_forward();
void process_backward();
int naive_until_mod(ULL val, int &beg, int end);
int
main()
{
cin.tie(0)->sync_with_stdio(0);
cin >> nops >> nqueries;
ops.resize(nops);
for (auto &op : ops) cin >> op.add >> op.mul;
ops.push_back({.add = 0, .mul = 1}); // dummy pos at the end
PrefSum linear_psum(ops);
process_forward();
process_backward();
REP (i, nops) debug(i, next_mul[i], add_combo[i]);
while (nqueries--) {
int start, l, r;
cin >> start >> l >> r;
start = naive_until_mod(start, l, r);
auto lrange = linear_psum.query(l, r);
auto res = Linear::compose(Linear{.a = 0, .b = start}, lrange);
cout << res.b << "\n";
}
return 0;
}
int
naive_until_mod(ULL val, int &beg, int end)
{
debug("naive", val, beg, end);
while (beg < end && val < MOD) {
const auto &op = ops[beg];
// Skip chunks with mul=1
if (op.always_add()) {
int go_to = min(next_mul[beg], end);
ULL to_add = add_combo[go_to - 1] - add_combo[beg] + op.add;
val += to_add, beg = go_to;
continue;
}
// We have a chunk with mul>1; this one executes at most 30 times
val = max(val + op.add, val * op.mul);
beg += 1;
}
debug("naive", val, beg, end);
return val % MOD;
}
void
process_forward()
{
add_combo.resize(nops);
if (ops[0].always_add()) add_combo[0] = ops[0].add;
FOR (i, 1, nops - 1) {
add_combo[i] = add_combo[i - 1] + ops[i].add;
if (!ops[i].always_add()) add_combo[i] = 0;
}
}
void
process_backward()
{
next_mul.resize(nops);
int mul_pos = nops;
for (int i = nops - 1; i >= 0; --i) {
next_mul[i] = mul_pos;
if (!ops[i].always_add()) mul_pos = i;
}
}
ostream &
operator<<(ostream &o, Linear f)
{
return o << make_pair(f.a, f.b);
}
int
fast_pow(int base, int exp)
{
int res = 1;
while (exp) {
if (exp & 1) res = mul(res, base);
base = mul(base, base);
exp >>= 1;
}
return res;
}
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 | // clang-format off #include<bits/stdc++.h> using namespace std; using ULL=unsigned long long; #define FOR(i,l,r) for(auto i=(l);i<=(r);++i) #define REP(i,n) FOR(i,0,(n)-1) #define ssize(x) int(x.size()) auto operator<<(ostream&o,auto p)->decltype(p.first,o){return o<<"("<<p.first<<", "<<p.second<<")";} auto operator<<(ostream&o,auto x)->decltype(x.end(),o){o<<"{";int i=0;for(auto e:x)o<<(", ")+2*!i++<<e;return o<<"}";} #ifdef DEBUG #define debug(x...) cerr<<"["#x"]: ",[](auto...$){((cerr<<$<<"; "),...);}(x),cerr<<'\n' #else #define debug(...) {} #endif // clang-format on const int MOD = 1000000000 + 7; // clang-format off int add(const int &a, const int &b) { return a + b >= MOD ? a + b - MOD : a + b; } int mul(const int &a, const int &b) { return 1LL * a * b % MOD; } int sub(const int &a, const int &b) { return a >= b ? a - b : MOD + a - b; } int fast_pow(int base, int exp); int modinv(const int& x) { return fast_pow(x, MOD - 2); } // clang-format on struct Linear { int a = 1, b = 0; static inline Linear compose(Linear f, Linear g) // apply f then g { return {mul(g.a, f.a), add(mul(g.a, f.b), g.b)}; } inline Linear inverse() { auto ai = modinv(a); return {.a = ai, .b = sub(0, mul(ai, b))}; } }; struct Option { int add, mul; inline bool always_add() const { return mul <= 1; } inline Linear linear() const { return always_add() ? Linear{.a = 1, .b = add} : Linear{.a = mul, .b = 0}; } }; struct PrefSum { vector<Linear> pref; PrefSum(const vector<Option> &ops) : pref(ops.size() + 1) { REP (i, ssize(ops)) pref[i + 1] = Linear::compose(pref[i], ops[i].linear()); } Linear query(int beg, int end) { return Linear::compose(pref[beg].inverse(), pref[end]); } }; int nops, nqueries; vector<Option> ops; // (add, or mul) vector<pair<int, Linear>> jp; // (pos, operations on the way to pos) vector<int> next_mul; vector<ULL> add_combo; // pref sum since last mul void process_forward(); void process_backward(); int naive_until_mod(ULL val, int &beg, int end); int main() { cin.tie(0)->sync_with_stdio(0); cin >> nops >> nqueries; ops.resize(nops); for (auto &op : ops) cin >> op.add >> op.mul; ops.push_back({.add = 0, .mul = 1}); // dummy pos at the end PrefSum linear_psum(ops); process_forward(); process_backward(); REP (i, nops) debug(i, next_mul[i], add_combo[i]); while (nqueries--) { int start, l, r; cin >> start >> l >> r; start = naive_until_mod(start, l, r); auto lrange = linear_psum.query(l, r); auto res = Linear::compose(Linear{.a = 0, .b = start}, lrange); cout << res.b << "\n"; } return 0; } int naive_until_mod(ULL val, int &beg, int end) { debug("naive", val, beg, end); while (beg < end && val < MOD) { const auto &op = ops[beg]; // Skip chunks with mul=1 if (op.always_add()) { int go_to = min(next_mul[beg], end); ULL to_add = add_combo[go_to - 1] - add_combo[beg] + op.add; val += to_add, beg = go_to; continue; } // We have a chunk with mul>1; this one executes at most 30 times val = max(val + op.add, val * op.mul); beg += 1; } debug("naive", val, beg, end); return val % MOD; } void process_forward() { add_combo.resize(nops); if (ops[0].always_add()) add_combo[0] = ops[0].add; FOR (i, 1, nops - 1) { add_combo[i] = add_combo[i - 1] + ops[i].add; if (!ops[i].always_add()) add_combo[i] = 0; } } void process_backward() { next_mul.resize(nops); int mul_pos = nops; for (int i = nops - 1; i >= 0; --i) { next_mul[i] = mul_pos; if (!ops[i].always_add()) mul_pos = i; } } ostream & operator<<(ostream &o, Linear f) { return o << make_pair(f.a, f.b); } int fast_pow(int base, int exp) { int res = 1; while (exp) { if (exp & 1) res = mul(res, base); base = mul(base, base); exp >>= 1; } return res; } |
English