51nod1370 排列与操作

可以发现,最后得到的序列一定是每个数是连续的一段,而且他们之间的相对顺序不变。除去那些和原来恰好一样的位置,段数就是操作次数。
于是可以dp,用 dp[i][j][k] 表示前 i 个位置,操作j次,目前覆盖到了 k 的方案数。枚举这一段覆盖的位置可以做到O(n)转移,这个转移可以前缀和优化,最后的复杂度是 O(n3) ,注意特殊处理这一段和原序列相同,也就是操作次数不增加的情况。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=210,oo=0x3f3f3f3f,p=1000000007;
int a[maxn],dp[maxn][maxn][maxn],left[maxn],right[maxn],tag[maxn],n,m;
void inc(int &x,int y)
{
    x+=y;
    x=(x>=p?x-p:x);
}
void dec(int &x,int y)
{
    x-=y;
    x=(x<0?x+p:x);
}
void solve()
{
    int ans=0;
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    a[0]=a[n+1]=oo;
    for (int i=1;i<=n;i++)
    {
        for (int j=i-1;j>=0;j--)
            if (a[j]>a[i])
            {
                left[i]=j;
                break;
            }
        for (int j=i+1;j<=n+1;j++)
            if (a[j]>a[i])
            {
                right[i]=j;
                break;
            }
    }
    memset(dp,0,sizeof(dp));
    dp[0][0][0]=1;
    for (int i=1;i<=n;i++)
        for (int j=0;j<=i&&j<=m;j++)
        {
            for (int k=0;k<=n;k++)
                inc(dp[i][j][k],dp[i-1][j][k]);
            memset(tag,0,sizeof(tag));
            for (int k=left[i];k<right[i]-1;k++)
                if (k==i-1)
                {
                    inc(dp[i][j][k+1],dp[i-1][j][k]);
                    inc(tag[k+2],dp[i-1][j][k]);
                }
                else inc(tag[k+1],dp[i-1][j][k]);
            for (int k=left[i]+1;k<right[i];k++)
            {
                inc(tag[k],tag[k-1]);
                inc(dp[i][j+1][k],tag[k]);
            }
        }
    for (int i=0;i<=m;i++) inc(ans,dp[n][i][n]);
    printf("%d\n",ans);
}
int main()
{
    //freopen("b.in","r",stdin);
    int T;
    scanf("%d",&T);
    while (T--) solve();
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值