51nod 1250 排列与交换

题目大意:你有一个初始为 1 n的顺序数组
问题一:恰好进行 k 次相邻交换,最后有多少不同的排列
问题二:进行不多于k次交换(不一定相邻),最后有多少种不同的排列
(n,k<=3000)
思路:这道题没有什么新意,其主要思路就是将恰好变为最少,即一个排列我们要用最少的操作次数得到。
对于第一问,考虑一个排列,我们要求出在最少交换次数的情况下如何得到它。
f[i][j] 为到第 i 个数,目前交换了j次得到的排列个数,那么每次转移就是直接把新的数往前面的序列里插,注意转移优化。
考虑交换相邻的数会导致总的逆序对的奇偶性发生反转,假设一个排列用 i 次得到,那么如果i k 奇偶性相同,则此排列一定可以满足恰好k次操作得到(我们可以无聊的交换i次得到的排列的相邻两项)
否则一定不可以得到(根据逆序对的奇偶性)
这样我们解决了第一问
第二问和第一问并没有什么区别,考虑这个可以两两交换,我们要在次数最少的情况下得到最终排列,从置换群的角度看最终的排列,构建有向图,发现最终排列的本质是一个个有向圈,很明显可以证明一个排列经过最少交换次数得到一定是从小到大插入有向圈里
根据这个性质我们直接设 f[i][j] 为前 i 个数使用了j次交换,那么每次相当于把一个数插入到有向圈里,直接转移就好啦。

代码:

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#define N 3000
using namespace std;
typedef long long LL;
LL ans,n,k,P,f[N + 5][N + 5];
int main(){
    cin>>n>>k;
    P = 1000000007LL;
    memset(f,0,sizeof(f));
    f[0][0] = 1;
    for (int i = 0;i < n; ++i){
      if (i) for (int j = 1;j <= k; ++j){
        f[i][j] = f[i][j - 1] + f[i][j];
        if (f[i][j] >= P) f[i][j] -= P;}
      for (int j = 0;j <= k; ++j){
        f[i + 1][j] = f[i + 1][j] +  f[i][j];
        if (f[i + 1][j] >= P) f[i + 1][j] -= P;
        if (i + j + 1 <= N) f[i + 1][j + i + 1] = f[i + 1][j + i + 1] - f[i][j];
        if (i + j + 1 <= N)if (f[i + 1][j + i + 1] < 0) f[i + 1][j + i + 1] += P;}
   }
    for (int i = 1;i <= k; ++i) f[n][i] =  (f[n][i] + f[n][i - 1]) % P;
    for (int i = 0;i <= k; ++i)
      if (!((k - i)&1))
    ans = (ans + f[n][i]) % P;
    if (ans < 0) ans += P;
    cout<<ans<<" ";
    memset(f,0,sizeof(f));
    f[0][0] = 1;
    for (int i = 1;i <= n; ++i){
      f[i][0] = f[i - 1][0];
      for (int j = 1;j <= k; ++j)
       f[i][j] = (f[i - 1][j] + f[i - 1][j - 1] * (i - 1) % P) % P;}
    ans = 0;
    for (int i = 0;i <= k; ++i) ans = (ans + f[n][i]) % P;
    cout<<ans;
    return 0;
}

总结:1.当求一些操作序列多少次的时候可以转化为在最少情况下得到,根据这个设计dp状态

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值