zoukankan      html  css  js  c++  java
  • [ZJOI2010]排列计数

    题目描述

    称一个1,2,...,N的排列P1,P2...,Pn是Magic的,当且仅当2<=i<=N时,Pi>Pi/2. 计算1,2,...N的排列中有多少是Magic的,答案可能很大,只能输出模P以后的值

    输入输出格式

    输入格式:

    输入文件的第一行包含两个整数 n和p,含义如上所述。

    输出格式:

    输出文件中仅包含一个整数,表示计算1,2,⋯, ���的排列中, Magic排列的个数模 p的值。

    输入输出样例

    输入样例#1:
    20 23 
    输出样例#1:
    16
    

    说明

    100%的数据中,1 ≤N ≤ 10^6, P≤ 10^9,p是一个质数。

    画图发现树的形状是唯一的

    且对于一个子树的根,一定小于所有子树节点

    也就是说,对于一个根节点,只要考虑给左右子树划分的方案
    可以列出dp方程:

    f[i]=f[2*i]*f[2*i+1]*C(size[2*i],size[2*i+1]+size[2*i])

    这题据说n会大于p,也就是说1~n会含有p

    那么就不能线性求逆元

    统计出i!中p出现的次数num[i]和不算p的倍数的阶乘fac[i]

    算组合数时,如果num[y]-num[x]-num[y-x]不为0直接返回0

    逆元直接把fac[]带入拓展欧几里德,因为在算fac时排除了p,所以可行

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<algorithm>
     4 #include<cstring>
     5 using namespace std;
     6 typedef long long lol;
     7 lol f[1000001],size[1000001],p,num[1000001],fac[1000001],n;
     8 lol exgcd(lol a,lol b,lol &x,lol &y)
     9 {
    10   if (b==0) 
    11     {
    12       x=1;y=0;
    13       return a;
    14     }
    15   lol d=exgcd(b,a%b,x,y);
    16   lol t=x;x=y;y=t-(a/b)*y;
    17   return d;
    18 }
    19 lol reverse(lol a)
    20 {
    21   lol x,y;
    22   exgcd(a,p,x,y);
    23   return (x%p+p)%p;
    24 }
    25 lol C(int x,int y)
    26 {
    27   lol ap=num[y],bp=num[x],cp=num[y-x];
    28   if (ap-bp-cp) return 0;
    29   lol s=(fac[y]*reverse(fac[x])%p)*reverse(fac[y-x])%p;
    30   return s;
    31 }
    32 void dfs_dp(int x)
    33 {
    34   f[x]=1;
    35   size[x]=1;
    36   if (2*x<=n)
    37     dfs_dp(2*x);
    38   if (2*x+1<=n)
    39     dfs_dp(2*x+1);
    40   if (2*x<=n)
    41   if (2*x+1>n||size[2*x+1]==0)
    42     {
    43       f[x]=f[2*x];
    44       size[x]+=size[2*x];
    45     }
    46   else 
    47     {
    48       f[x]=((f[2*x]*f[2*x+1]%p)*C(size[2*x],size[2*x]+size[2*x+1])%p)%p;
    49       size[x]+=size[2*x]+size[2*x+1];
    50     }
    51 }
    52 int main()
    53 {int i;
    54   cin>>n>>p;
    55   fac[0]=1;
    56   for (i=1;i<=n;i++)
    57     {
    58       int x=i;
    59       num[i]=num[i-1];
    60        while (x%p==0)
    61     {
    62       num[i]++;
    63       x/=p;
    64     }
    65        if (i%p==0) fac[i]=fac[i-1];
    66        else fac[i]=fac[i-1]*i%p;
    67     }
    68   dfs_dp(1);
    69   cout<<f[1];
    70 }
  • 相关阅读:
    Thinking in java(八)-正则表达式
    order by与索引
    order by与索引
    004_常量的设置
    008_ajax没有跳转页面的错误
    007_缺少aspactj依赖
    006_为什么我的本机地址是0.0.0.0.0.1
    005_mybatis逆向工程错误
    004_当用数据库账号密码不对时?
    059_SSM——JDK动态代理是怎么回事?它又是怎么运用到了SSM框架中的?
  • 原文地址:https://www.cnblogs.com/Y-E-T-I/p/7642821.html
Copyright © 2011-2022 走看看