CF285 E Positions in Permutations——“恰好->大于”的容斥和允许“随意放”的dp

题目:http://codeforces.com/contest/285/problem/E

是2018.7.31的一场考试的题,当时没做出来。

题解:http://www.cnblogs.com/yanshannan/p/9410986.html

因为那个值对于 i 位置来说只和 i 位置放了 i-1 或 i+1 有关,所以状态里记录一下 i 和 i+1 有没有已经放过,再加上 i-1 的对于 i-1 和 i 的状态,就能转移了。

枚举这一位:放 i-1 /放 i+1/先空下。先空下对那个值无影响,所以可以做到;最后相当于指定了 j 个位置放什么值,剩下的位置乘上一个排列即可。

随便往空下的位置放可能导致多一些值,所以最后容斥一下即可。

注意初值赋给那个状态!

那场考试的其余信息就见 Zinn 的博客吧。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const int N=1005,mod=1e9+7;
int n,m,dp[N][N][2][2],jc[N],jcn[N],ans,f[N];
int pw(int x,int k)
{int ret=1;while(k){if(k&1ll)ret=(ll)ret*x%mod;x=(ll)x*x%mod;k>>=1ll;}return ret;}
void init()
{
  jc[0]=1; for(int i=1;i<=n;i++) jc[i]=(ll)jc[i-1]*i%mod;
  jcn[n]=pw(jc[n],mod-2);
  for(int i=n-1;i>=0;i--) jcn[i]=(ll)jcn[i+1]*(i+1)%mod;
}
void upd(int &x){x-=(x>=mod?mod:0);}
int C(int n,int m){return (ll)jc[n]*jcn[m]%mod*jcn[n-m]%mod;}
int main()
{
  scanf("%d%d",&n,&m);
  init();
  dp[0][0][1][0]=1;//so pos1 can't 0!!!!!!
  for(int i=1;i<=n;i++)
    for(int j=0;j<=n;j++)//n
    for(int k=0;k<=1;k++)
      {
        dp[i][j][k][0]=dp[i-1][j][0][k]+dp[i-1][j][1][k],
          upd(dp[i][j][k][0]);//rand
        if(j)dp[i][j][k][1]=dp[i-1][j-1][0][k]+dp[i-1][j-1][1][k],
           upd(dp[i][j][k][1]),//i+1
           dp[i][j][k][0]+=dp[i-1][j-1][0][k],
           upd(dp[i][j][k][0]);//i-1
      }
  for(int i=m;i<=n;i++)
    f[i]=(ll)(dp[n][i][0][0]+dp[n][i][1][0])*jc[n-i]%mod;
  ans=f[m];
  for(int i=m+1,fx=-1;i<=n;i++,fx=-fx)
    ans+=(ll)f[i]*C(i,i-m)%mod*fx,ans+=(fx==1?0:mod),upd(ans);
  printf("%d\n",ans);
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/Narh/p/9651971.html
今日推荐