zoukankan      html  css  js  c++  java
  • [CF285E] Positions in Permutations

    https://zybuluo.com/ysner/note/1236806

    题面

    称一个(1-n)的排列的完美数为有多少个(i)满足(|P_i−i|=1)
    求有多少个长度为(n)的完美数恰好为(m)的排列。

    • (n,mleq1000)

    解析

    因为要计数,所以(DP)
    显然状态中要包含一些信息:统计第(1-i)个数的答案、有(j)个满足条件、(i-1)(i+1)二数是否被用过。
    但是如果真这样设状态,就只能隔一个数转移一次(因为得到(i-1)的信息必须通过(i-2))。
    边界状态不好设计啊。
    然后我懵了

    实际上,应该设(f[i][j][k_{(2)}][l_{(2)}])表示在第(1-i)个数中,已经填了(j)个满足条件的数,(k)表示(i)是否已填,(l)表示(i+1)是否已填。
    这样一切都顺理成章了。
    决策三种:

    • 这一位先不填数(最后把设定不符合条件的数乱填一下)
    • 这一位填(i-1)
    • 这一位填(i+1)

    这样(ans[m]=(dp[n][m][0][0]+dp[n][m][1][0])*2^{n-m})(另外两状态不合法)

    最后考虑计重问题。
    这时得到的(ans[m])是完美数(geq m)的所有方案。
    (ans[m])包含了(ans[m+1])中的(C_{m+1}^m)种方案。
    (ans[m])包含了(ans[m+2])中的(C_{m+2}^m)种方案。
    于是乘上组合数容斥一波即可。

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    #define re register
    #define il inline
    #define ll long long
    #define max(a,b) ((a)>(b)?(a):(b))
    #define min(a,b) ((a)<(b)?(a):(b))
    #define fp(i,a,b) for(re int i=a;i<=b;i++)
    #define fq(i,a,b) for(re int i=a;i>=b;i--)
    using namespace std;
    const int mod=1e9+7,N=6e5+100;
    int n,m;
    ll dp[1005][1005][2][2],C[1005][1005],ans[1005],jc[1005],anss;
    il ll gi()
    {
       re ll x=0,t=1;
       re char ch=getchar();
       while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar();
       if(ch=='-') t=-1,ch=getchar();
       while(ch>='0'&&ch<='9') x=x*10+ch-48,ch=getchar();
       return x*t;
    }
    int main()
    {
      n=gi();m=gi();
      C[0][0]=1;
      fp(i,1,n)
        {
          C[i][0]=1;
          fp(j,1,i) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mod;
        }
      jc[0]=1;fp(i,1,n) jc[i]=(jc[i-1]*i)%mod;
      dp[0][0][1][0]=1;
      fp(i,1,n)
        fp(j,0,i)
        fp(k,0,1)
        fp(l,0,1)
        {
          (dp[i][j][l][0]+=dp[i-1][j][k][l])%=mod;//不管
          if(j&&k==0) (dp[i][j][l][0]+=dp[i-1][j-1][k][l])%=mod;//取i-1
          if(j) (dp[i][j][l][1]+=dp[i-1][j-1][k][l])%=mod;//取i+1
        }
      fp(i,0,n) (ans[i]+=dp[n][i][0][0]+dp[n][i][1][0])%=mod,ans[i]=ans[i]*jc[n-i]%mod;
      anss=ans[m];
      re int flag=-1;
      fp(i,m+1,n) anss=(anss+flag*ans[i]*C[i][m]%mod+mod)%mod,flag=-flag;
      printf("%lld
    ",anss);
      return 0;
    }
    
  • 相关阅读:
    Codeforces Round #541 (Div. 2) D 并查集 + 拓扑排序
    Educational Codeforces Round 60 D dp + 矩阵快速幂
    Educational Codeforces Round 60 C 思维 + 二分
    Codeforces Round #544 (Div. 3) dp + 双指针
    Codeforces Round #542(Div. 2) CDE 思维场
    UVA
    UVA
    UVA
    UVA
    UVA
  • 原文地址:https://www.cnblogs.com/yanshannan/p/9410986.html
Copyright © 2011-2022 走看看