#include <bits/stdc++.h>
#include <ext/pb_ds/assoc_container.hpp>
#include <ext/pb_ds/tree_policy.hpp>
using namespace std;
using namespace __gnu_pbds;
typedef long long ll;
typedef long double ld;
mt19937 rng(chrono::steady_clock::now().time_since_epoch().count());
int random(int st, int dr)
{
uniform_int_distribution<int> dist(st, dr);
return dist(rng);
}
template <typename t>
using ordered_set = tree<t, null_type, less<t>, rb_tree_tag, tree_order_statistics_node_update>;
const int mod = 1e9 + 7;
struct Mint
{
int val;
Mint(int x = 0)
{
val = x % mod;
}
Mint(long long x)
{
val = x % mod;
}
Mint operator+(Mint oth)
{
return val + oth.val;
}
Mint operator-(Mint oth)
{
return val - oth.val + mod;
}
Mint operator*(Mint oth)
{
return 1ll * val * oth.val;
}
void operator+=(Mint oth)
{
val = (*this + oth).val;
}
void operator-=(Mint oth)
{
val = (*this - oth).val;
}
void operator*=(Mint oth)
{
val = (*this * oth).val;
}
};
Mint powmod(int a, int b)
{
if (b == 0)
{
return 1;
}
if (b % 2 == 1)
{
return powmod(a, b - 1) * a;
}
Mint p = powmod(a, b / 2);
return p * p;
}
/*
.___ __ __ .__
____ ____ __| _/____ _______/ |______ ________/ |_ ______ | |__ ___________ ____
_/ ___\/ _ \ / __ |/ __ \ / ___/\ __\__ \\_ __ \ __\/ ___/ | | \_/ __ \_ __ \_/ __ \
\ \__( <_> ) /_/ \ ___/ \___ \ | | / __ \| | \/| | \___ \ | Y \ ___/| | \/\ ___/
\___ >____/\____ |\___ > /____ > |__| (____ /__| |__| /____ > |___| /\___ >__| \___ >
\/ \/ \/ \/ \/ \/ \/ \/ \/
*/
const int nmax = 5e5;
const int sigma = 26;
Mint dp[nmax + 1][sigma + 1][3];
Mint sum[nmax + 1][sigma + 1][3];
struct rmq
{
vector<vector<int>> maxi;
vector<int> lg;
rmq(int n, vector<int> a)
{
lg.resize(n + 1);
for (int i = 2; i <= n; ++i)
{
lg[i] = lg[i / 2] + 1;
}
maxi.resize(n + 1, vector<int>(lg[n] + 1));
for (int i = 1; i <= n; ++i)
{
maxi[i][0] = a[i];
}
for (int j = 1; j <= lg[n]; ++j)
{
for (int i = 1; i + (1 << j) - 1 <= n; ++i)
{
maxi[i][j] = max(maxi[i][j - 1], maxi[i + (1 << (j - 1))][j - 1]);
}
}
};
int query(int st, int dr)
{
int pow_2 = lg[dr - st + 1];
return max(maxi[st][pow_2], maxi[dr - (1 << pow_2) + 1][pow_2]);
}
};
Mint query(int x1, int x2, int y1, int y2, int need)
{
return sum[x2][y2][need] - sum[x1 - 1][y2][need] - sum[x2][y1 - 1][need] + sum[x1 - 1][y1 - 1][need];
};
int32_t main()
{
cin.tie(nullptr)->sync_with_stdio(false);
int n, m;
cin >> n >> m;
vector<vector<int>> a(2, vector<int>(n + 1));
for (int i = 1; i <= m; ++i)
{
int x, y;
cin >> x >> y;
if (x < y)
{
a[0][x] = max(a[0][x], y);
}
else
{
a[1][y] = max(a[1][y], x);
}
}
rmq adam0(n, a[0]), adam1(n, a[1]);
vector<vector<tuple<int, int, int>>> events(n + 1);
for (int i = 1; i <= n; ++i)
{
int rep1 = 0, rep2 = 0;
int st = 1, dr = i;
while (st <= dr)
{
int mid = (st + dr) / 2;
if (adam0.query(mid, i) > i)
{
rep1 = mid;
st = mid + 1;
}
else
{
dr = mid - 1;
}
}
st = 1, dr = i;
while (st <= dr)
{
int mid = (st + dr) / 2;
if (adam1.query(mid, i) > i)
{
rep2 = mid;
st = mid + 1;
}
else
{
dr = mid - 1;
}
}
int coef = rep1 > rep2 ? 1 : 2;
events[i].push_back({max(rep1, rep2) + 1, i, 0});
events[i].push_back({min(rep1, rep2) + 1, max(rep1, rep2), coef});
}
for (int i = 1; i <= n; ++i)
{
for (int s = 1; s <= sigma; ++s)
{
for (auto [st, dr, need] : events[i])
{
if (st > dr)
{
continue;
}
if (st == 1)
{
dp[i][s][need] += 1;
st++;
}
if (st > dr)
{
continue;
}
for (int need2 = 0; need2 <= 2; ++need2)
{
int opus = 3 ^ need2;
if (opus & 1)
{
dp[i][s][need] += query(st - 1, dr - 1, 1, s - 1, need2);
}
if (opus & 2)
{
dp[i][s][need] += query(st - 1, dr - 1, s + 1, sigma, need2);
}
}
}
}
for (int s = 1; s <= sigma; ++s)
{
for (int need = 0; need <= 2; ++need)
{
sum[i][s][need] = sum[i - 1][s][need] + sum[i][s - 1][need] - sum[i - 1][s - 1][need] + dp[i][s][need];
}
}
}
Mint ans = 0;
for (int i = 1; i <= sigma; ++i)
{
ans += dp[n][i][0];
}
cout << ans.val << '\n';
}
/*
I cannot take this anymore
Saying everything I've said before
All these words, they make no sense
I find bliss in ignorance
Less I hear, the less you say
You'll find that out anyway
Just like before
Everything you say to me
(Takes me one step closer to the edge)
(And I'm about to break)
I need a little room to breathe
(Cause I'm one step closer to the edge)
(I'm about to break)
*/
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |
# | Verdict | Execution time | Memory | Grader output |
---|
Fetching results... |