poj3761(反序表)

博客围绕POJ - 3761题目展开,题目要求计算通过k趟冒泡排序得到长为n的有序排列的原排列个数。通过引入反序表概念及相关结论,将问题转化为求最大反序数为k的反序表个数,给出计算方法,最后通过打表阶乘和快速幂取模求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:https://vjudge.net/problem/POJ-3761

题意:给出n和k,求通过k趟冒泡排序得到长为n的有序排列(元素为n个不同的数)的原排列有多少个。

思路:

先给出反序表的定义:

  令bi(1<=i<=n)為位於i左邊但是大於i的元素個數,就能得到排列a1,a2,...,an的反序表b1,b2,...,b3。比如說,排列5 9 1 8 2 6 4 7 3有反序表2 3 6 4 0 2 2 1 0(在1左邊且大於1的有2個,在2左邊且大於2的有3個,……)。

再给出反序表的重要结论:

  第1個元素的反序數取值範圍是[0,n-1],第i個元素的反序數取值範圍是[0,n-i],最後一個元素的反序數只能是0。并且每個反序數可以在區間內任意取值而不用考慮其他反序數的值,也就是說反序數是相互獨立的。(因为第一个元素的反序数[0,n-1]分别对应n个位置中的一个位置,确定之后去掉这个位置,剩下n-1个位置; 第二个元素的反序数[0,n-1]对应这n-1个位置中的一个,确定之后去掉这个位置,剩下n-2个位置......这样可以得到所有反序表对应的原排列有n!个,原排列本身最多只有n!个,所以反序表和原排列是一一对应的,且反序表中反序数相互独立。)

回到题目:

  不难发现每一趟冒泡排序都会将剩下的>0的反序数减一,所以题目就转变乘最大反序数为k的反序表个数。所以我们可以通过求最大反序数<=k的反序表的个数,元素i的反序数为n-i,令n-i<=k得i>=n-k,即>=n-k的元素其反序数恒<=k,所以其反序数的值可以是其范围内的任意值,共有(k+1)!种可能。对于i<n-k,其反序数范围为[0,k],即k+1种,则共有(k+1)^(n-k-1)种可能。两者相乘得k!*(k+1)^(n-k)。

  同理求出最大反序数<=k-1的个数,相减得k!*[(k+1)^(n-k)-k^(n-k)]。

  然后打表阶乘,利用快速幂取模即可。

AC代码:

#include<cstdio>
using namespace std;
typedef long long LL;
const int maxn=1000005;
const int Mod=20100713;

int T;
LL f1[maxn];

void init(){
    f1[0]=f1[1]=1;
    for(int i=2;i<=1000000;++i)
        f1[i]=f1[i-1]*i%Mod;
}

LL qpow(LL a,LL b){
    LL ans=1;
    while(b){
        if(b&1) ans=(ans*a)%Mod;
        a=(a*a)%Mod;
        b>>=1;
    }
    return ans;
}

int main(){
    init();
    scanf("%d",&T);
    while(T--){
        LL n,k;
        scanf("%lld%lld",&n,&k);
        printf("%lld\n",f1[k]*(qpow(k+1,n-k)-qpow(k,n-k)+1LL*Mod)%Mod);
    }
    return 0;
}

 

 

 

转载于:https://www.cnblogs.com/FrankChen831X/p/10809243.html

<think>好的,我现在需要帮助用户查找POJ上与链相关的题目以及对应的解法。首先,我需要明确用户的需。他们可能正在准备算法竞赛或练习数据结构,特别是链相关的题目。POJ是一个知名的在线评测平台,题目数量众多,所以需要筛选出与链相关的题目。 首先,我应该回忆一下POJ上常见的链题目类型。链在算法题中的应用通常包括单链、双向链、循环链,以及使用链解决特定问题,比如约瑟夫环、块状链等。此外,有些题目可能需要结合其他数据结构,比如线段树或者并查集,但用户特别提到链,所以应聚焦于核心链问题。 接下来,我需要参考用户提供的引用内容。引用[3]提到了POJ#2828-Buy Tickets,这道题使用了线段树、块状链和STL中的rope。虽然rope属于STL的扩展容器,但块状链可能属于链的一种变体。因此,这道题可以作为链相关题目之一推荐给用户,并解释其中的链应用部分。 然后,我应该列出其他常见的POJ题目。例如,约瑟夫环问题(Joseph problem)通常用循环链来模拟,POJ上可能有相关的题目编号,比如POJ 3750。另外,链的基本操作题,如反转链、合并链等,可能在POJ上也有对应的题目,但具体题号需要确认。 此外,块状链(如引用[3]中的rope)在解决某些插入、删除操作频繁的问题时效率较高,可以作为一个高级链结构进行介绍。用户可能对这类优化方法感兴趣。 在解法方面,链题的常见解法包括直接模拟(如用指针或数组实现链)、利用其他数据结构优化(如块状链减少时间复杂度)、或者数学方法(如约瑟夫环的递推公式)。需要根据具体题目类型来推荐不同的解法策略。 现在,我需要确保推荐的题目和解法准确,并且符合用户的需。可能需要检查每个题目的具体内容,确保它们确实涉及链。例如,POJ 2828确实需要高效的插入操作,使用块状链或STL的rope来实现,这属于链的一种应用。而约瑟夫环问题通常用循环链模拟,但也可以使用数学方法优化。 另外,用户可能希望了解不同解法的优缺点,比如时间复杂度和空间复杂度,以及在不同情况下的适用性。例如,直接模拟链操作可能在数据量大时超时,这时候就需要更高效的块状链或数学方法。 最后,总结出几个典型的POJ题目,并给出对应的解法和技巧,帮助用户有针对性地练习和掌握链相关的数据结构和算法。</think>### POJ相关题目及解法 以下是POJ平台中涉及链结构的典型题目及解法分析: --- #### 1. **POJ 2828-Buy Tickets**[^3] **题意**:队列中不断有人插队,最终输出完整队列。需要处理$n$次插入操作,每次在指定位置插入数值。 **链解法**: - **块状链**:将链分块存储,每次插入操作时间复杂度降低到$O(\sqrt{n})$,适合大规模数据。 - **STL rope**:C++扩展库中的可持久化数据结构,底层基于平衡树,但操作类似链(如`insert(pos, val)`)。 **示例代码片段**: ```cpp #include <ext/rope> using namespace __gnu_cxx; rope<int> Q; Q.insert(pos, val); // 在位置pos插入值val ``` --- #### 2. **POJ 3750-小孩报数问题(约瑟夫环)** **题意**:$n$个人围成环,从第$k$个开始报数,每次数到$m$的人出列,最后剩下的人。 **链解法**: - **循环链模拟**:直接构建循环链,每次删除第$m$个节点,时间复杂度$O(nm)$。 - **数学递推公式**:优化时间复杂度到$O(n)$,公式为$f(n)=(f(n-1)+m)\ \%\ n$,其中$f(1)=0$[^1]。 --- #### 3. **POJ 3481-Double Queue(双向链应用)** **题意**:实现一个支持按优先级插入、删除最高/最低优先级元素的双向队列。 **链解法**: - **平衡树(如STL map)**:直接利用红黑树实现$O(\log n)$操作。 - **双向链+哈希**:手动维护有序双向链,配合哈希快速定位节点。 --- ### 链题通用解法技巧 1. **数组模拟链**: 用`pre[]`和`nxt[]`数组代替指针,提升访问速度(如POJ 3272)。 2. **块状链优化**: 将链分块,降低频繁插入/删除的开销(如POJ 2828)[^3]。 3. **结合其他数据结构**: 如并查集维护连通性(POJ 1308),或线段树加速区间查询。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值