2017 Chinese Multi-University Training, BeihangU Contest 部分题解

比赛链接

 

Problem A. Add More Zero

温暖的签到题。

#include<bits/stdc++.h>
using namespace std ;
int main()
{
    std::ios::sync_with_stdio(false) , cin.tie(0) ;
    double m ;
    int cas = 0 ;
    while(cin >> m)
    {
        cout << "Case #" << ++ cas << ": " ;
        m *= log10(2) ;
        cout << (int)m << '\n' ;
    }
    return 0 ;
}

 

Problem B. Balala Power!

先把每个字符的权值都当成1,把每种字符的贡献算出来,然后按照贡献从大到小排序依次分配25,24,\cdots,0

注意前导0

#include<bits/stdc++.h>
using namespace std ;
const int mod = 1e9 + 7 ;
const int maxn = 1e5 + 1e4 + 10 ;
int cnt[30][maxn] ;
int mx[30] ;
bool vis[30] ;
int pre[maxn] ;
bool zero[30] ;
int main()
{
    std::ios::sync_with_stdio(false) , cin.tie(0) ;
    int n ;
    int cas = 0 ;
    pre[0] = 1 ;
    for(int i = 1 ; i <= 1e5 + 1e4 ; i ++)  pre[i] = 1ll * pre[i - 1] * 26 % mod ;
    while(cin >> n)
    {
        cout << "Case #" << ++ cas << ": " ;
        memset(cnt , 0 , sizeof(cnt)) ;
        memset(mx , -1 , sizeof(mx)) ;
        memset(vis , false , sizeof(vis)) ;
        memset(zero , false , sizeof(zero)) ;
        while(n --)
        {
            string s ;
            cin >> s ;
            int len = s.size() ;
            for(int i = 0 ; i < len ; i ++)
            {
                int p = len - 1 - i ;
                cnt[s[i] - 'a'][p] ++ ;
                mx[s[i] - 'a'] = max(mx[s[i] - 'a'] , p) ;
            }
            if(len > 1)  zero[s[0] - 'a'] = true ;
        }
        for(int i = 0 ; i < 26 ; i ++)
        {
            for(int j = 0 ; j <= mx[i] + 50 ; j ++)
            {
                cnt[i][j + 1] += cnt[i][j] / 26 ;
                cnt[i][j] %= 26 ; 
            }
            for(int j = mx[i] + 50 ; j >= 0 ; j --)
                if(cnt[i][j] > 0)  mx[i] = max(mx[i] , j) ;
        }
        vector<int> v ;
        int ans = 0 ;
        for(int i = 0 ; i < 26 ; i ++)
        {
            int id = -1 ;
            for(int j = 0 ; j < 26 ; j ++)
            {
                if(vis[j])  continue ;
                if(id == -1)
                {
                    id = j ;
                    continue ;
                }
                if(mx[j] < mx[id])  continue ;
                if(mx[j] > mx[id])
                {
                    id = j ;
                    continue ;
                }
                for(int k = mx[j] ; k >= 0 ; k --)
                {
                    if(cnt[j][k] > cnt[id][k])
                    {
                        id = j ;
                        break ;
                    }
                    else if(cnt[j][k] == cnt[id][k])  continue ;
                    else  break ;
                }
            }
            vis[id] = true ;
            v.push_back(id) ;
        }
        int t ;
        for(int i = 25 ; i >= 0 ; i --)
        {
            if(!zero[v[i]])
            {
                t = i ;
                break ;
            }
        }
        //cout << t << '\n' ;
        int tmp = v[t] ;
        for(int i = t ; i < 25 ; i ++)  v[i] = v[i + 1] ;
        v[25] = tmp ;
        for(int i = 0 ; i < 25 ; i ++)
        {
            int id = v[i] ;
            for(int j = 0 ; j <= mx[id] ; j ++)  
                ans += 1ll * cnt[id][j] * (25 - i) * pre[j] % mod , ans %= mod ;
        }
        cout << ans << '\n' ;
    }
    return 0 ;
}

 

Problem C. Colorful Tree

考虑容斥,对于每种颜色,统计不包含该种颜色的路径数。

对于一个不包含第i种颜色的极大联通子图G,设G的大小是siz,答案减去C(siz,2)即可。

其实一个dfs就完事,具体细节看代码。

#include<bits/stdc++.h>
using namespace std ;
int main()
{
    std::ios::sync_with_stdio(false) , cin.tie(0) ;
    int n ;
    int cas = 0 ;
    while(cin >> n)
    {
        cout << "Case #" << ++ cas << ": " ;
        vector<int> c(n + 1) ;
        for(int i = 1 ; i <= n ; i ++)  cin >> c[i] ;
        vector<vector<int>> g(n + 1) ; 
        for(int i = 1 ; i <= n - 1 ; i ++)
        {
            int u , v ;
            cin >> u >> v ;
            g[u].push_back(v) ;
            g[v].push_back(u) ;
        }
        long long ans = 1ll * n * n * (n - 1) / 2 ;
        vector<int> d(n + 1 , 0) ;
        vector<int> siz(n + 1 , 0) ;
        function<long long(int)> C = [&](int x)
        {
            return 1ll * x * (x - 1) / 2 ;
        } ;
        function<void(int , int)> dfs = [&](int fa , int u)
        {
            int tmp = d[c[u]] ;
            siz[u] = 1 ;
            for(auto v : g[u])
            {
                if(v == fa)  continue ;
                d[c[u]] = tmp ;   
                dfs(u , v) ;
                ans -= C(siz[v] - (d[c[u]] - tmp)) ;
                siz[u] += siz[v] ;
            }
            d[c[u]] = tmp + siz[u] ;
        } ;
        dfs(1 , 1) ;
        for(int i = 1 ; i <= n ; i ++)  ans -= C(n - d[i]) ;
        cout << ans << '\n' ;
    }
    return 0 ;
}   

 

Problem D. Division Game

留坑。

 

Problem E. Expectation of Division

留坑。

 

Problem F. Function

每个排列a中长度为l的环,都可以映射到b中长度是l的因子的环。累加贡献即可。

#include<bits/stdc++.h>
using namespace std ;
const int mod = 1e9 + 7 ;
int main()
{
    std::ios::sync_with_stdio(false) , cin.tie(0) ;
    int n , m ;
    int cas = 0 ;
    while(cin >> n >> m)
    {
        cout << "Case #" << ++ cas << ": " ;
        vector<int> a(n) ;
        vector<int> b(m) ;
        for(int i = 0 ; i < n ; i ++)  cin >> a[i] ;
        for(int i = 0 ; i < m ; i ++)  cin >> b[i] ;
        vector<bool> vis1(n , false) ;
        vector<bool> vis2(m , false) ;
        vector<int> cnt1(n + 1 , 0) ;
        vector<int> cnt2(m + 1 , 0) ;
        int cnt = 0 ;
        function<void(int)> dfs1 = [&](int u)
        {
            if(vis1[u])  return ;
            vis1[u] = true ;
            cnt ++ ;
            dfs1(a[u]) ;
        } ;
        for(int i = 0 ; i < n ; i ++)
            if(!vis1[i])  cnt = 0 , dfs1(i) , cnt1[cnt] ++ ;
        cnt = 0 ;
        function<void(int)> dfs2 = [&](int u)
        {
            if(vis2[u])  return ;
            vis2[u] = true ;
            cnt ++ ;
            dfs2(b[u]) ;
        } ;
        for(int i = 0 ; i < m ; i ++)
            if(!vis2[i])  cnt = 0 , dfs2(i) , cnt2[cnt] ++ ;
        vector<int> c(n + 1 , 0) ;
        for(int i = 1 ; i <= m ; i ++)
            for(int j = i ; j <= n ; j += i)
                c[j] += 1ll * cnt2[i] * i % mod , c[j] %= mod ;
        //for(int i = 1 ; i <= n ; i ++)  cout << i << ' ' << c[i] << '\n' ;
        bool flag = true ;
        long long ans = 1 ;
        for(int i = 1 ; i <= n ; i ++)
            if(cnt1[i] > 0)
            {
                //cout << i << ' ' << cnt1[i] << '\n' ;
                if(c[i] == 0)  flag = false ;
                else  for(int j = 1 ; j <= cnt1[i] ; j ++)  ans *= c[i] , ans %= mod ;
            }
        if(!flag)  ans = 0 ;
        cout << ans << '\n' ;
    }
    return 0 ;
}

 

Problem G. Gear Up

这道题搞了好几个小时。刚开始题解半天看不懂啥意思,什么**父亲儿子角速度线速度的。

后来太烦了,手动画了几个图才搞明白是个啥,其实很简单。主要是要耐心画图。

本质是若干棵树组成的森林,每个节点其实是一个连通块,连通块内的齿轮角速度相同。边其实就代表着线速度相同。

每个连通块内的若干个节点会与父亲的连通块内节点和儿子的连通块内节点相连。具体关系需要手推了,说不清楚,题解其实说的也没法立刻明白啥意思。

主要考的是dfs序和线段树。不过外面套的壳太神了,需要耐心剥开。

#include<bits/stdc++.h>
#define pb push_back
#define fi first
#define se second
#define sz(x)  (int)x.size()
#define cl(x)  x.clear()
#define all(x)  x.begin() , x.end()
#define rep(i , x , n)  for(int i = x ; i <= n ; i ++)
#define per(i , n , x)  for(int i = n ; i >= x ; i --)
#define mem0(x)  memset(x , 0 , sizeof(x))
#define mem_1(x)  memset(x , -1 , sizeof(x))
#define mem_inf(x)  memset(x , 0x3f , sizeof(x))
#define debug(x)  cerr << #x << " = " << x << '\n'
#define ddebug(x , y)  cerr << #x << " = " << x << "   " << #y << " = " << y << '\n'
#define ios std::ios::sync_with_stdio(false) , cin.tie(0)
using namespace std ;
typedef long long ll ;
typedef long double ld ;
typedef pair<int , int> pii ;
typedef pair<ll , ll> pll ;
typedef double db ;
const int mod = 998244353 ;
const int maxn = 1e5 + 10 ;
const int inf = 0x3f3f3f3f ;
const double eps = 1e-6 ;
int n , m , q ;
int r[maxn] ;
vector<int> g[maxn] ;
vector<int> c[maxn] ;
bool vis[maxn] ;
int p[maxn] ;
int cnt ;
int dfn[maxn] ;
int siz[maxn] ;
int anc[maxn] ;
int L[maxn] , R[maxn] ;
bool fa[maxn] ;
bool son[maxn] ;
int l1[maxn] , r1[maxn] ;
struct Dsu
{
    int pre[maxn] , siz[maxn] ;
    void init(int n)
    {
        for(int i = 1 ; i <= n ; i ++)  pre[i] = i , siz[i] = 1 ;
    }
    int find(int u) 
    {
        if(pre[u] == u)  return u ;
        return pre[u] = find(pre[u]) ;
    }
    void join(int x , int y)
    {
        int fx = find(x) ;
        int fy = find(y) ;
        if(fx != fy)  
        {
            if(siz[fx] <= siz[fy])  pre[fx] = fy , siz[fy] += siz[fx] ;
            else  pre[fy] = fx , siz[fx] += siz[fy] ;
        }       
    }
} dsu ;
struct seg_tree
{
    int max1[maxn << 2] , lazy[maxn << 2] ;  
    int ls(int x){ return x << 1 ; }
    int rs(int x){ return x << 1 | 1 ; }
    void push_up(int p){ max1[p] = max(max1[ls(p)] , max1[rs(p)]) ; }
    void build(int id , int l , int r)
    {
        lazy[id] = 0 ;
        if(l == r) {max1[id] = p[l] ; return ;}
        int mid = (l + r) >> 1 ;
        build(ls(id) , l , mid) ;
        build(rs(id) , mid + 1 , r) ;
        push_up(id) ;
    } 
    void f(int id , int l , int r , int k)
    {
        lazy[id] += k ;
        max1[id] += k ;
    }
    void push_down(int id , int l , int r)
    {
        int mid = (l + r) >> 1 ;
        f(ls(id) , l , mid , lazy[id]) ;
        f(rs(id) , mid + 1 , r , lazy[id]) ;
        lazy[id] = 0 ;
    }
    void add(int id , int l , int r , int x , int y , int k)
    {
        if(x > y || x > r || y < l)  return ;
        if(x <= l && r <= y)
        {
            max1[id] += k ;
            lazy[id] += k ;
            return ;
        }
        push_down (id , l , r) ;
        int mid = (l + r) >> 1 ;
        if(x <= mid)  add(ls(id) , l , mid , x , y , k) ;
        if(y > mid)   add(rs(id) , mid + 1 , r , x , y , k) ;
        push_up(id) ;
    }
    int query(int id , int l , int r , int x , int y)
    {
        if(x > y || x > r || y < l)  return inf ;
        int ans = -1e9 ;
        if(x <= l && r <= y) return max1[id] ; 
        int mid = (l + r) >> 1 ;
        push_down(id , l , r) ;
        if(x <= mid) ans = max(ans , query(ls(id) , l , mid , x , y)) ;
        if(y > mid)  ans = max(ans , query(rs(id) , mid + 1 , r , x , y)) ;
        return ans ;
    }
} seg ;
void dfs(int u , int val , int t)
{
    dfn[u] = ++ cnt ;
    p[dfn[u]] = val ;
    siz[dfn[u]] = 1 ;
    anc[u] = t ;
    L[u] = cnt ;
    for(auto x : c[u])
    {
        vis[x] = true ;
        for(auto v : g[x])
        {
            if(vis[v])  continue ;
            son[x] = true ;
            fa[v] = true ;
            l1[x] = min(l1[x] , cnt + 1) ;
            dfs(dsu.find(v) , val + r[x] - r[v] , t) ;
            //cout << "###  " << x << ' ' << L[x] << ' ' << R[x] << '\n' ;
            siz[dfn[u]] += siz[dfn[dsu.find(v)]] ;
            r1[x] = cnt ;
        }
    }
    R[u] = cnt ;
}
int main()
{
    ios ;
    int cas = 0 ;
    while(cin >> n >> m >> q)
    {
        cout << "Case #" << ++ cas << ":\n" ;
        dsu.init(n) ;
        for(int i = 1 ; i <= n ; i ++)  cin >> r[i] , r[i] = __builtin_ctz(r[i]) ;
        for(int i = 1 ; i <= n ; i ++)  g[i].clear() ;
        for(int i = 1 ; i <= n ; i ++)  c[i].clear() ;
        for(int i = 0 ; i < m ; i ++)
        {
            int a , x , y ;
            cin >> a >> x >> y ;
            if(a == 1)  g[x].push_back(y) , g[y].push_back(x) ;
            else  dsu.join(x , y) ;
        }
        for(int i = 1 ; i <= n ; i ++)  c[dsu.find(i)].push_back(i) ;
        memset(vis , false , sizeof(vis)) ;
        memset(p , 0 , sizeof(p)) ;
        cnt = 0 ;
        memset(dfn , 0 , sizeof(dfn)) ;
        memset(siz , 0 , sizeof(siz)) ;
        memset(anc , 0 , sizeof(anc)) ;
        memset(L , 0x3f , sizeof(L)) ;
        memset(R , 0 , sizeof(R)) ;
        memset(l1 , 0x3f , sizeof(l1)) ;
        memset(r1 , 0 , sizeof(r1)) ;
        memset(fa , false , sizeof(fa)) ;
        memset(son , false , sizeof(son)) ;
        for(int i = 1 ; i <= n ; i ++)  
            if(!vis[i] && i == dsu.find(i))  dfs(i , 0 , i) ;
        seg.build(1 , 1 , cnt) ;
        //for(int i = )
        // cout << "!!! " << cnt << '\n' ;
        // for(int i = 1 ; i <= cnt ; i ++)
        //     cout << "??? " << seg.query(1 , 1 , cnt , i , i) << '\n' ;
        while(q --)
        {
            int a , x , y ;
            cin >> a >> x >> y ;
            y = __builtin_ctz(y) ;
            if(a == 1)  
            {
                int tmp = y - r[x] ;
                int rt = dsu.find(x) ;
                if(fa[x])  seg.add(1 , 1 , cnt , L[rt] , R[rt] , -tmp) ;
                if(son[x])  seg.add(1 , 1 , cnt , l1[x] , r1[x] , tmp) ;
                r[x] = y ;
                // cout << "!!! " << cnt << '\n' ;
                // for(int i = 1 ; i <= cnt ; i ++)
                //     cout << "??? " << seg.query(1 , 1 , cnt , i , i) << '\n' ;
            }
            else
            {
                int now = seg.query(1 , 1 , cnt , dfn[dsu.find(x)] , dfn[dsu.find(x)]) ;
                int f = y - now ;
                int rt = anc[dsu.find(x)] ;
                int ans = f + seg.query(1 , 1 , cnt , L[rt] , R[rt]) ;
                cout << fixed << setprecision(3) << ans * log(2) << '\n' ;
                //cout << ans << '\n' ;
            }
        }
    }
    return 0 ;
}

 

Problem H. Hints of sd0061

nth\_element函数线性求区间第k大。

#include<bits/stdc++.h>
using namespace std ;
const int maxn = 1e7 + 10 ;
int n , m ;
unsigned a[maxn] ;
unsigned ans[105] ;
struct node
{
    int id , x ;
    bool operator < (const node &s) const
    {
        return x < s.x ;
    }
} b[105] ;
unsigned A , B , C ;
unsigned x , y , z ;
unsigned rng61() 
{
    unsigned t ;
    x = x ^ (x << 16) ;
    x = x ^ (x >> 5) ;
    x = x ^ (x << 1) ;
    t = x ;
    x = y ;
    y = z ;
    z = ( t ^ x ) ^ y ;
    return z ;
}
int main()
{
    std::ios::sync_with_stdio(false) , cin.tie(0) ;
    int n , m ;
    int cas = 0 ;
    while(cin >> n >> m >> A >> B >> C)
    {
        cout << "Case #" << ++ cas << ": " ;
        x = A , y = B , z = C ;
        for(int i = 1 ; i <= n ; i ++)  a[i] = rng61() ;
        for(int i = 1 ; i <= m ; i ++)  cin >> b[i].x , b[i].id = i , b[i].x ++ ;
        sort(b + 1 , b + m + 1) ;
        for(int i = m ; i >= 1 ; i --)
        {
            if(i + 1 <= m && b[i].x == b[i + 1].x)  ans[b[i].id] = ans[b[i + 1].id] ;
            else
            {
                if(i == m)  nth_element(a + 1 , a + b[i].x , a + n + 1) ;
                else  nth_element(a + 1 , a + b[i].x , a + b[i + 1].x + 1) ;
                ans[b[i].id] = a[b[i].x] ;
            }
        }
        for(int i = 1 ; i <= m ; i ++)  cout << ans[i] << " \n"[i == m] ;
    }
    return 0 ;
}

 

Problem I. I Curse Myself

有点神的题。

因为是个仙人掌,所以可以去掉的非树边都在环上,相当于是每个环上去掉一条边。

因此题目转化为若干个序列,每个序列选择一个数,对这些数求和,询问第k大的和。

本质是多个序列的合并问题,如果直接用大小为kset维护合并过程的话,复杂度是O(M*k*log(k)),其中M是若干个序列元素个数和。

设第i个序列的元素个数是m_i,考虑用大小为m_i的堆维护,这样复杂度是O(M*k)

复杂度证明可以通过求导推出来。具体维护过程看代码的merge函数。

调了半天,还好一发过了。

#include<bits/stdc++.h>
using namespace std ;
int main()
{
    std::ios::sync_with_stdio(false) , cin.tie(0) ;
    int n , m ;
    int cas = 0 ;
    while(cin >> n >> m)
    {
        cout << "Case #" << ++ cas << ": " ;
        vector<vector<pair<int , unsigned>>> g(n + 1) ;
        unsigned ans = 0 ;
        unsigned sum = 0 ;
        for(int i = 1 ; i <= m ; i ++)
        {
            int u , v , w ;
            cin >> u >> v >> w ;
            g[u].push_back({v , w}) ;
            g[v].push_back({u , w}) ;
            sum += w ;
        }
        unsigned k ;
        cin >> k ;
        vector<pair<int , unsigned>> pre(n + 1) ;
        vector<bool> vis(n + 1 , false) ;
        vector<unsigned> res ;
        vector<unsigned> val ;
        vector<unsigned> tmp ;
        vector<unsigned> c(m + 1) ;
        vector<unsigned> dfn(n + 1 , 0) ;
        int cur = 0 ;
        res.push_back(0) ;
        function<void()> merge = [&]()
        {
            priority_queue<pair<unsigned , int>> q ;
            int m = val.size() ;
            sort(val.begin() , val.end()) ;
            reverse(val.begin() , val.end()) ;
            for(int i = 0 ; i < m ; i ++)
            {
                c[i] = 0 ;
                q.push({val[i] + res[0] , i}) ;
            }
            tmp.clear() ;
            while(!q.empty() && tmp.size() < k)
            {
                auto now = q.top() ;
                q.pop() ;
                tmp.push_back(now.first) ;
                c[now.second] ++ ;
                if(c[now.second] < res.size())  
                    q.push({val[now.second] + res[c[now.second]] , now.second}) ;
            }
            swap(tmp , res) ;
        } ;
        function<void(int , int)> path = [&](int u , int anc)
        {
            if(u == anc)  return ;
            path(pre[u].first , anc) ;
            val.push_back(pre[u].second) ;
        } ;
        function<void(int , int)> dfs = [&](int fa , int u)
        {
            vis[u] = true ;
            dfn[u] = ++ cur ;
            for(auto x : g[u])
            {
                int v = x.first ;
                unsigned w = x.second ;
                if(v == fa)  continue ;
                if(vis[v] && dfn[v] > dfn[u])  continue ;
                if(vis[v] && dfn[v] < dfn[u])
                {
                    val.clear() ;
                    val.push_back(w) ;
                    path(u , v) ;
                    merge() ;
                    continue ;
                }
                pre[v] = {u , w} ;
                dfs(u , v) ;
            }
        } ;
        dfs(1 , 1) ;
        for(unsigned i = 0 ; i < res.size() ; i ++)  ans += (i + 1) * (sum - res[i]) ;
        cout << ans << '\n' ;
    }
    return 0 ;
}   

 

Problem J. Journey with Knapsack

留坑。

 

Problem K. KazaQ’s Socks

手动模拟发现循环节即可。

#include<bits/stdc++.h>
using namespace std ;
int main()
{
    std::ios::sync_with_stdio(false) , cin.tie(0) ;
    int n ;
    long long k ;
    int cas = 0 ;
    while(cin >> n >> k)
    {
        cout << "Case #" << ++ cas << ": " ;
        if(n == 2)
        {
            if(k % 2 == 1)  cout << "1\n" ;
            else  cout << "2\n" ;
        }
        else
        {
            if(k <= n)  cout << k << '\n' ;
            else
            {
                k -= n ;
                k %= 2 * (n - 1) ;
                if(k == 0)  cout << n << '\n' ;
                else if(k <= n - 1)  cout << k << '\n' ;
                else  cout << k - (n - 1) << '\n' ;
            }
        }
    }
    return 0 ;
}   

 

Problem L. Limited Permutation

分治裸题。

对于以p_{id}为最小值的[l,r]这段区间,f(l,r)=C(r-l,id-l)*f(l,id-1)*f(id+1,r)f(l,r)是这段区间的贡献。

注意判断无解即可。

#include<bits/stdc++.h>
using namespace std ;
const int mod = 1e9 + 7 ;
const int maxn = 1e6 + 10 ;
typedef long long ll ;
ll inv1[maxn] ;  //乘法逆元
void init1(int up)
{
   inv1[1] = 1 ;
   for(int i = 2 ; i <= up ; i ++)
     inv1[i] = (ll)(mod - mod / i) * inv1[int(mod % (ll)i)] % mod ;
}
ll fac[maxn] ;
ll inv[maxn] ; //阶乘逆元
void init(int up) 
{
   fac[0] = fac[1] = inv[0] = inv[1] = 1 ;
   for(int i = 2 ; i <= up ; i ++)
   {
     fac[i] = fac[i - 1] * i % mod ;
     inv[i] = -inv[mod % i] * (mod / i) % mod ;
     while(inv[i] < 0) inv[i] += mod ;
   }
   for(int i = 2 ; i <= up ; i ++)  
     inv[i] = inv[i] * inv[i - 1] % mod ;
}
ll C(int n , int m)
{
    return fac[n] * inv[m] % mod * inv[n - m] % mod ;
}
int main()
{
    std::ios::sync_with_stdio(false) , cin.tie(0) ;
    int n ;
    int cas = 0 ;
    init(1000000) ;
    while(cin >> n)
    {
        cout << "Case #" << ++ cas << ": " ;
        vector<int> l(n + 1) ;
        vector<int> r(n + 1) ;
        for(int i = 1 ; i <= n ; i ++)  cin >> l[i] ;
        for(int i = 1 ; i <= n ; i ++)  cin >> r[i] ;
        vector<vector<pair<int , int>>> pos(n + 1) ;
        vector<int> cur(n + 1 , 0) ;
        for(int i = 1 ; i <= n ; i ++)  pos[l[i]].push_back({r[i] , i}) ;
        for(int i = 1 ; i <= n ; i ++)  
            sort(pos[i].begin() , pos[i].end()) , reverse(pos[i].begin() , pos[i].end()) ;
        function<long long(int , int)> solve = [&](int l , int r)
        {
            if(l > r)  return 1ll ;
            if(cur[l] == pos[l].size())  return 0ll ;
            int nxt = pos[l][cur[l]].first ;
            if(nxt != r)  return 0ll ;
            int id = pos[l][cur[l]].second ;
            cur[l] ++ ;
            return C(r - l , id - l) * solve(l , id - 1) % mod * solve(id + 1 , r) % mod ;
        } ;
        cout << solve(1 , n) << '\n' ;
    }
    return 0 ;
}   

 

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值