bzoj 2445 最大团 CRT 组合数取模

来源:互联网 发布:美国反智主义 知乎 编辑:程序博客网 时间:2024/05/17 12:51

题意太迷。。。
其实就是求n个点symmetric labeled cliquer的个数,然后取一个m次幂。
答案就是

mx|nn!(x!)nx(nx!)

把mod-1分解质因数,把这个数分别取模mod-1的因子,然后用CRT合并。

不过这个东西不是组合数,不能用lucas。可以先预处理阶乘,用礼物的方法做,会比lucas多个log,不过这题还挺快的。

#include <bits/stdc++.h>using namespace std;#define mod 999999599#define ll long long#define PA pair<int,int> #define N 8100int p[5]={2,13,5281,7283};int n,m,T;int a[5],jc[5][N];int qpow(int x,int y,int md){    int ret=1;    while(y)    {        if(y&1)ret=(ll)ret*x%md;        x=(ll)x*x%md;y>>=1;    }    return ret;}void init(){    for(int i=0;i<4;i++)    {        jc[i][0]=1;        for(int j=1;j<p[i];j++)            jc[i][j]=jc[i][j-1]*j%p[i];    }}void exgcd(ll &x,ll &y,int a,int b){    if(b==0){x=1;y=0;return;}    exgcd(y,x,b,a%b);y-=a/b*x;}PA get(int x,int tp,int md){    if(x==0)return make_pair(1,0);    int t=x/md;    PA r1=get(t,tp,md);    return make_pair(qpow(jc[tp][md-1],t,md)*    jc[tp][x-t*md]%md*r1.first%md,r1.second+t);}void cal(int x){    for(int i=0;i<4;i++)    {        PA t1=get(n,i,p[i]),t2=get(x,i,p[i]),t3=get(n/x,i,p[i]);        if(t1.second-t2.second*(n/x)-t3.second)continue;        a[i]=(a[i]+t1.first*qpow(qpow(t2.first,n/x,p[i])*t3.first%p[i],p[i]-2,p[i])%p[i])%p[i];    }}int CRT(int md){    int ret=0;    ll x,y;    for(int i=0;i<4;i++)    {        exgcd(x,y,md/p[i],p[i]);        x=(x%p[i]+p[i])%p[i];        ret=(ret+md/p[i]*x%md*a[i]%md)%md;    }    return ret;}int main(){       //freopen("tt.in","r",stdin);    init();    scanf("%d",&T);    while(T--)    {           memset(a,0,sizeof(a));        scanf("%d%d",&n,&m);        for(int i=1;(ll)i*i<=n;i++)            if(n%i==0)            {                cal(i);                if(i*i!=n)cal(n/i);            }        printf("%d\n",qpow(m,CRT(mod-1),mod));    }    return 0;}
0 0
原创粉丝点击