zoukankan      html  css  js  c++  java
  • [国家集训队] 礼物

    洛谷 P2183 传送门

    bzoj 2142 传送门

    一共n个礼物,分给m个人,每个人分wi个。

    如果不够分,当然是Impossible。

    如果够分,考虑求出1-n的所有排列,然后前w1个分给第一个人,w2个分给第二个人......

    剩下的那些,当做分给了第m+1个人。

    这样共有 n! 种排列。

    但是每个人(包括第m+1个)分到的礼物只要本质一样就行,排列顺序无所谓。

    所以我们再除掉 w1!、w2!、...、wm+1! 就行了。

    取模数为非质数,用扩展卢卡斯的方法计算阶乘即可。

     最开始全WA,调了一下发现是逆元求错了......求x逆元的函数会return x......

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 typedef long long ll;
     6 
     7 int n,m;
     8 ll p;
     9 ll w[8];
    10 ll ans;
    11 
    12 ll ksm(ll bs,ll tp,ll mod)
    13 {
    14     ll ret=1;
    15     while(tp)
    16     {
    17         if(tp&1)ret=ret*bs%mod;
    18         bs=bs*bs%mod;
    19         tp>>=1;
    20     }
    21     return ret;
    22 }
    23 
    24 ll exgcd(ll a,ll b,ll &x,ll &y)
    25 {
    26     if(!b)
    27     {
    28         x=1;y=0;
    29         return a;
    30     }
    31     ll ret=exgcd(b,a%b,y,x);
    32     y-=a/b*x;
    33     return ret;
    34 }
    35 
    36 ll inv(ll x,ll mod)
    37 {
    38     ll ret,tmp;
    39     exgcd(x,mod,ret,tmp);
    40     return (ret%mod+mod)%mod;
    41 }
    42 
    43 ll crt(ll a,ll pk)
    44 {
    45     return a*(p/pk)%p*inv(p/pk,pk)%p;
    46 }
    47 
    48 ll fac(ll x,ll pi,ll pk)
    49 {
    50     if(!x)return 1;
    51     ll ret=1;
    52     for(ll i=2;i<=pk;i++)
    53         if(i%pi)ret=ret*i%pk;
    54     ret=ksm(ret,x/pk,pk);
    55     for(ll i=2;i<=x%pk;i++)
    56         if(i%pi)ret=ret*i%pk;
    57     return ret*fac(x/pi,pi,pk)%pk;
    58 }
    59 
    60 void cal(ll pi,ll pk)
    61 {
    62     ll cnt=0;
    63     ll up=fac(n,pi,pk);
    64     for(ll i=n;i;i/=pi)cnt+=i/pi;
    65     ll down=1;
    66     for(int j=1;j<=m;j++)
    67     {
    68         down=down*fac(w[j],pi,pk)%pk;
    69         for(ll i=w[j];i;i/=pi)cnt-=i/pi;
    70     }
    71     ll tmp=up*inv(down,pk)%pk*ksm(pi,cnt,pk)%pk;
    72     ans=(ans+crt(tmp,pk))%p;
    73 }
    74 
    75 int main()
    76 {
    77     scanf("%lld",&p);
    78     scanf("%d%d",&n,&m);
    79     w[m+1]=(ll)n;
    80     for(int i=1;i<=m;i++)scanf("%lld",&w[i]),w[m+1]-=w[i];
    81     m++;
    82     if(w[m]<0)return printf("Impossible"),0;
    83     ll tp=p;
    84     for(ll i=2;i*i<=p;i++)
    85     {
    86         if(tp%i)continue;
    87         ll pk=1;
    88         while(tp%i==0)tp/=i,pk*=i;
    89         cal(i,pk);
    90     }
    91     if(tp>1)cal(tp,tp);
    92     printf("%lld",ans);
    93     return 0;
    94 }
  • 相关阅读:
    如何启用apache的gzip压缩?
    Zend Framework配置Nginx的rewrite
    数据库差异比较工具
    心愿王泽 杨颖 乔媛 唐景莲
    在所有存储过程中查找一个关键字
    通用分页存储过程
    JavaScript开发工具 Aptana
    js如何控制select控件(下拉列表)
    Read and write flat file
    Extreme Programming
  • 原文地址:https://www.cnblogs.com/cervusy/p/9903222.html
Copyright © 2011-2022 走看看