zoukankan      html  css  js  c++  java
  • 【ZJOI2010】排列计数

    题面

    https://www.luogu.org/problem/P2606

    题解

    数列按广度优先搜索序搜索,变成一个堆。所以形态是给定的。

    只需记忆化搜索就可以了,复杂度$O(logn)$。顺序递推亦可。

    对于阶乘超过$p$的情况,我们把$p$的次幂记下来,算的时候直接减去。$aysn$说这是卢卡斯定理,我只能$orz$了。

    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    #define ri register int
    #define N 1000500
    #define LL long long
    using namespace std;
    
    int n,p;
    int jc[N],inv[N],jcp[N],invp[N];
    
    int C1(int a,int b) {
      if (a==b || a==0) return 0;
      return jcp[b]+invp[a]+invp[b-a];
    }
    int C2(int a,int b) {
      if (a==b || a==0) return 1;
      return ((jc[b]*1LL*inv[a])%p*1LL*inv[b-a])%p;
    }
    
    LL solve1(int x) {
      if (x==1 || x==0) return 0;
      for (ri i=20;i>=0;i--) if (x&(1<<i)) {
        if (x&(1<<(i-1))) 
          return solve1((1<<i)-1)+solve1(x-(1<<i))+C1((1<<i)-1,x-1);
        else 
          return solve1(x-(1<<(i-1)))+solve1((1<<(i-1))-1)+C1((1<<(i-1))-1,x-1);
      }
    }
    LL solve2(int x) {
      if (x==1 || x==0) return 1;
      for (ri i=20;i>=0;i--) if (x&(1<<i)) {
        if (x&(1<<(i-1))) 
          return ((solve2((1<<i)-1)*solve2(x^(1<<i)))%p*C2((1<<i)-1,x-1))%p;
        else
          return (solve2(x-(1<<(i-1)))*solve2((1<<(i-1))-1)%p*C2((1<<(i-1))-1,x-1))%p;
      }
    }
    
    int pow(int a,int b) {
      int ret=1;
      for (;b;b>>=1,a=(a*1LL*a)%p) if (b&1) ret=(ret*1LL*a)%p;
      return ret;
    }
    
    int count(int x) {
      int ret=0;
      while (x%p==0) x/=p,ret++;
      return ret;
    }
    
    int main() {
      cin>>n>>p;
      jc[0]=jc[1]=1;
      for (ri i=2;i<N;i++) if (i%p) {
        jc[i]=(jc[i-1]*1LL*i)%p;
        jcp[i]=jcp[i-1];
      }
      else {
        jc[i]=jc[i-1];
        jcp[i]=jcp[i-1]+count(i);
      }
      inv[N-1]=pow(jc[N-1],p-2);
      invp[N-1]=-jcp[N-1];
      
      for (ri i=N-2;i>=1;i--) if ((i+1)%p) {
        inv[i]=(inv[i+1]*1LL*(i+1))%p;
        invp[i]=invp[i+1];
      }
      else {
        inv[i]=inv[i+1];
        invp[i]=invp[i+1]+count(i+1);
      }
      if (solve1(n)==0) cout<<solve2(n)<<endl; else cout<<0<<endl;
      return 0;
    }
  • 相关阅读:
    【C++】<bits/stdc++.h>
    【网易】被3整除
    【TCP/IP详解】UDP:用户数据报协议
    【网易】牛牛找工作
    【C++】<numeric>中iota函数:递增序列填充

    今天好像找到C语言延迟输出的原因了
    C语言第2
    c语言新知
    glade No package 'libxml-2.0' found
  • 原文地址:https://www.cnblogs.com/shxnb666/p/11460964.html
Copyright © 2011-2022 走看看