codeforces Edu 142 D. Fixed Prefix Permutations 【思维、字典树求LCP】

文章讲述了如何利用Trie数据结构解决给定排列问题,通过计算排列的逆序并查找最长公共前缀(LCP),找到每对排列的最大公共部分价值。时间复杂度为O(nm)。
摘要由CSDN通过智能技术生成

D. Fixed Prefix Permutations

D

题意

给定 n n n 个长度为 m m m排列 a 1 , a 2 , . . . a n a_1,a_2,...a_n a1,a2,...an

定义一个排列 p p p价值最大顺序长度 k k k p 1 = 1 , p 2 = 2 , p 3 = 3 , . . . p k = k p_1 = 1,p_2 = 2, p_3 = 3, ... p_k = k p1=1,p2=2,p3=3,...pk=k,如果 p 1 ≠ 1 p_1 \neq 1 p1=1,那么 p p p 的价值为 0 0 0

定义两个排列的 乘积 为: p ⋅ q = r ,其中 r j = q p j p \cdot q = r,其中 r_j = q_{p_j} pq=r,其中rj=qpj

现在对于每个 i ∈ [ 1 , n ] i \in [1, n] i[1,n],求出 最大 a i ⋅ a j a_i \cdot a_j aiaj(注意 j j j 可以等于 i i i

思路

对于当前的 a i a_i ai,我们需要找到一个 j j j,使得 a i ⋅ a j = ( 1 , 2 , 3 , 4 , . . . . k , r k + 1 , . . . . r m ) a_i \cdot a_j = (1,2,3,4,....k, r_{k + 1},....r_m) aiaj=(1,2,3,4,....k,rk+1,....rm) 中的 k k k 最大
如果 k k k 刚好等于 m m m 的话, a i ⋅ a j = ( 1 , 2 , 3 , 4 , . . . . , m ) a_i \cdot a_j = (1, 2, 3, 4,...., m) aiaj=(1,2,3,4,....,m)

此时我们转换一下: a i = ( 1 , 2 , 3 , 4 , . . . , m ) ⋅ a j − 1 a_i = (1,2,3,4,..., m) \cdot a_j ^ {-1} ai=(1,2,3,4,...,m)aj1

不难发现,对于一个顺序度为 m m m 的排列 ( 1 , 2 , 3 , 4 , . . . , m ) (1,2,3,4, ..., m) (1,2,3,4,...,m),它乘上 a j − 1 a_j ^ {-1} aj1 不会改变 a j − 1 a_j ^ {-1} aj1 的内容

也就是: a i = a j − 1 a_i = a_j ^ {-1} ai=aj1
更一般地,当 k < m k < m k<m 时, a i a_i ai 的前 k k k 位 与 a j − 1 a_j ^ {-1} aj1 的前 k k k 位是 一样 的!

那么我们只需要求出每个 a i a_i ai,然后再与当前的 a i a_i ai 比较,最长公共前缀就是当前 a i a_i ai 的答案

如何求逆?由 p ⋅ p − 1 = [ 1 , 2 , 3 , 4 , . . . , m ] p \cdot p ^ {-1} = [1,2,3,4,..., m] pp1=[1,2,3,4,...,m] 得: p p j − 1 = j p ^ {-1}_{p_j} = j ppj1=j,也就是以 p p p 为下标映射, p j p_j pj 指向的位置一定得为 j j j

那么我们只需要将每个逆存在 T r i e Trie Trie 上,对于当前的 a i a_i ai T r i e Trie Trie 上跑 L C P LCP LCP (最大公共前缀)即可

时间复杂度: O ( n m ) O(nm) O(nm)

#include<bits/stdc++.h>
#define fore(i,l,r)	for(int i=(int)(l);i<(int)(r);++i)
#define fi first
#define se second
#define endl '\n'
#define ull unsigned long long
#define ALL(v) v.begin(), v.end()
#define Debug(x, ed) std::cerr << #x << " = " << x << ed;

const int INF=0x3f3f3f3f;
const long long INFLL=1e18;

typedef long long ll;

const int N = 500050;

struct node{
    int son[11];
}tree[N];

int cnt = 0;

int main(){
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);
    std::cout.tie(nullptr);
    int t;
    std::cin >> t;
    while(t--){
        int n, m;
        std::cin >> n >> m;
        std::vector<int> ans(n + 1, 0);
        std::vector<std::vector<int>> a(n + 1, std::vector<int>(m + 1, 0));

        fore(i, 1, n + 1)
            fore(j, 1, m + 1)
                std::cin >> a[i][j];
        
        fore(i, 1, n + 1){
            std::vector<int> b(m + 1);
            fore(j, 1, m + 1) b[a[i][j]] = j;
            int now = 0;
            fore(j, 1, m + 1){ //Trie 插入 排列的逆
                int val =  b[j];
                if(!tree[now].son[val]) tree[now].son[val] = ++cnt;
                now = tree[now].son[val];
            }
        }

        fore(i, 1, n + 1){
            int now = 0;
            fore(j, 1, m + 1){ //Trie 查询最长前缀
                int val = a[i][j];
                if(!tree[now].son[val]) break;
                ++ans[i];
                now = tree[now].son[val];
            }
        }

        fore(i, 1, n + 1) std::cout << ans[i] << " \n"[i == n];

        fore(i, 0, cnt + 1) //清空 Trie
            fore(j, 1, m + 1)
                tree[i].son[j] = 0;
        cnt = 0;
    }
    return 0;
}
  • 15
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值