• bzoj 2142 : 礼物


    求$C_{n}^{m}\%p$。

    把p拆成$p1^{q1}*p2^{q2}...$最后用CRT合并。

    把每个阶乘拆成$x*p^y$的形式,因为x与$p^q$互质,可以直接用Euler定理求逆元,y就直接减。

    拆的时候把每个p的倍数提出一个p,变为$tmp*(p^x*(1*2*3*4...))$,tmp为与p互质的数,在$mod p^q$下有循环节,后半部分递归解决。

      1 #include<iostream>
      2 #include<cstdio>
      3 #include<algorithm>
      4 #include<cstring>
      5 #define N 100005
      6 #define int long long
      7 #define pa pair<int,int>
      8 #define mp make_pair
      9 using namespace std;
     10 int xx,yy;
     11 bool flag;
     12 int pw(int x,int y,int p)
     13 {
     14     if(!x)return 0;
     15     x%=p;
     16     int lst=1;
     17     while(y)
     18     {
     19         if(y&1)lst=lst*x%p;
     20         y>>=1;
     21         x=x*x%p;
     22     }
     23     return lst;
     24 }
     25 void exgcd(int a,int b)
     26 {
     27     if(b==0)
     28     {
     29         xx=1;yy=0;
     30         return ;
     31     }
     32     exgcd(b,a%b);
     33     int tmp=xx;
     34     xx=yy;
     35     yy=tmp-(a/b)*yy;
     36     return ;
     37 }
     38 int ans[100],p,n,m,w[10],s[100],su[100],tot;
     39 int jie[15][N];
     40 pa fact(int k,int n)
     41 {
     42     if(!n)return mp(1,0);
     43     int x=n/s[k];int ass=1;
     44     int y=n/su[k];
     45     if(y)
     46     {
     47         for(int i=2;i<su[k];i++)
     48         {
     49             if(i%s[k]!=0)ass=ass*i%su[k];
     50         }
     51         ass=pw(ass,y,su[k]);
     52     }
     53     for(int i=y*su[k]+1;i<=n;i++)
     54     {
     55         if(i%s[k]!=0)ass=ass*i%su[k];
     56     }
     57     pa tmp=fact(k,x);
     58     return mp(ass*tmp.first%su[k],x+tmp.second);
     59 }
     60 int qiu(int x,int y)
     61 {
     62     exgcd(x,y);
     63     return (x%y+y)%y;
     64 }    
     65 int lus(int n,int m,int x)
     66 {
     67     if(m>n)return 0;
     68     pa a=fact(x,n),b=fact(x,m),c=fact(x,n-m);
     69     int num=a.second-b.second-c.second;
     70     int q=a.first*pw(b.first,su[x]/s[x]*(s[x]-1)-1,su[x])%su[x]*pw(c.first,su[x]/s[x]*(s[x]-1)-1,su[x])%su[x];
     71     return pw(s[x],num,su[x])*q%su[x];
     72 }
     73 void div(int x)
     74 {
     75     for(int i=2;i*i<=x;i++)
     76     {
     77         if(x%i==0)
     78         {
     79             tot++;su[tot]=1;s[tot]=i;
     80             while(x%i==0)su[tot]*=i,x/=i;
     81         }
     82     }
     83     if(x!=1)su[++tot]=x,s[tot]=x;
     84 }
     85 void yu(int x)
     86 {
     87     jie[x][0]=1;
     88     for(int i=1;i<s[x];i++)jie[x][i]=jie[x][i-1]*i%su[x];
     89 }
     90 signed main()
     91 {
     92     scanf("%lld%lld%lld",&p,&n,&m);
     93     for(int i=1;i<=m;i++)scanf("%lld",&w[i]),w[i]+=w[i-1];
     94     if(n<w[m]){puts("Impossible");return 0;}
     95     div(p);
     96     for(int i=1;i<=tot;i++)yu(i);
     97     for(int i=1;i<=tot;i++)
     98     {
     99         ans[i]=1;
    100         for(int j=1;j<=m;j++)ans[i]=ans[i]*lus(n-w[j-1],w[j]-w[j-1],i)%su[i];
    101     }
    102     if(tot==1)
    103     {
    104         printf("%lld
    ",ans[1]);
    105         return 0;
    106     }
    107     int as=0;
    108     for(int i=1;i<=tot;i++)
    109     {
    110         int tmp=p/su[i];
    111         exgcd(tmp,su[i]);
    112         xx=(xx%su[i]+su[i])%su[i];
    113         xx=xx*tmp%p;
    114         as+=xx*ans[i]%p;
    115         as%=p;
    116     }
    117     printf("%lld
    ",as);
    118     return 0;
    119 }
  • 相关阅读:
    P2590 [ZJOI2008]树的统计(树链剖分)
    【算法】线性排序
    【LeetCode每天一题】Median of Two Sorted Arrays(两数组中的中位数)
    【算法】归并排序
    【LeetCode每天一题】Longest Substring Without Repeating Characters(最长无重复的字串)
    【算法】快排
    【LeetCode每天一题】Add Two Numbers(两链表相加)
    【LeetCode每天一题】Two Sum(两数之和)
    【算法】选择排序
    【算法】插入排序
  • 原文地址:https://www.cnblogs.com/ezyzy/p/6590660.html
Copyright © 2020-2023  润新知