• 解题:SHOI 2006 有色图


    题面

    本质上是在对边求置换,然后每个循环里涂一样的颜色,但是还是要点上入手,考虑每条边的两个端点是否在一个循环里

    如果在一个循环里,那么当循环长度$len$为奇数时只有转一整圈才行,而边的总数是$frac{len(len-1)}{2}$,所以有$frac{frac{len(len-1)}{2}}{len}=leftlfloorfrac{len}{2} ight floor$个循环节;当循环长度为偶数时除了上面这种情况正对的每对点旋转$frac{len}{2}$就可以,所以也是有$frac{frac{len(len-1)}{2}-frac{len}{2}}{len}+frac{frac{len}{2}}{frac{len}{2}}=leftlfloorfrac{len}{2} ight floor$个循环节

    如果不在一个循环里,那循环节数量就是套路的两者所在循环长度的GCD

    那么暴搜数的拆分得到每种点置换就可以求出答案了,具体的,在总共$n!$种点置换中,每个循环节$i$自己做圆排列除去$len[i]$,同时每个长度的循环节之间的排列也要除去,所以设$cnt[i]$表示长度为$i$的循环节的数量,那么满足拆分$len[1],len[2],len[3].....len[m]$的点置换的方案数就是

    $frac{n!}{prodlimits_{i=1}^mlen[i]prodlimits_{i=1}^mcnt[i]!}$

     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 const int N=64;
     6 int n,m,p,ans,fac[N],inv[N],len[N];
     7 int GCD(int a,int b)
     8 {
     9     return b?GCD(b,a%b):a;
    10 }
    11 int Qpow(int x,int k)
    12 {
    13     if(k==1) return x;
    14     int tmp=Qpow(x,k/2);
    15     return k%2?1ll*tmp*tmp%p*x%p:1ll*tmp*tmp%p;
    16 }
    17 int Inv(int x)
    18 {
    19     return Qpow(x,p-2);
    20 }
    21 void Calc(int cnt)
    22 {
    23     int pts=1,bas=1,lst=1,sum=0;
    24     for(int i=1;i<=cnt;i++) 
    25     {
    26         bas=1ll*bas*len[i]%p;
    27         if(len[i]!=len[lst])     
    28             bas=1ll*bas*fac[i-lst]%p,lst=i;
    29     }
    30     bas=1ll*bas*fac[cnt-lst+1]%p;
    31     pts=1ll*fac[n]*Inv(bas)%p;
    32     for(int i=1;i<=cnt;i++)
    33     {
    34         sum+=len[i]/2;
    35         for(int j=i+1;j<=cnt;j++)
    36             sum+=GCD(len[i],len[j]);
    37     }
    38     ans=(ans+1ll*pts*Qpow(m,sum)%p)%p;
    39 }
    40 void DFS(int cnt,int mnn,int mxx)
    41 {
    42     if(!mxx) Calc(cnt);
    43     else
    44         for(int i=mnn;i<=mxx;i++)
    45             len[cnt+1]=i,DFS(cnt+1,i,mxx-i);
    46 }
    47 int main()
    48 {
    49     scanf("%d%d%d",&n,&m,&p);
    50     fac[0]=inv[0]=1;
    51     for(int i=1;i<=n;i++) fac[i]=1ll*fac[i-1]*i%p;
    52     inv[n]=Inv(fac[n]);
    53     for(int i=n-1;i;i--) inv[i]=1ll*inv[i+1]*(i+1)%p;
    54     DFS(0,1,n),printf("%lld",1ll*ans*inv[n]%p);
    55     return 0;
    56 }
    View Code
  • 相关阅读:
    字符串中部分字符替换
    斐波那契数列
    单列模式--代码
    selenium基础知识
    关于页面元素不能定位,通过Js进行处理
    Linux性能监控工具命令--top
    java实现selenium jquery滑动解锁
    PHP学习(三)——连接MySQL数据库理论
    PHP学习(二)
    PHP学习(一)
  • 原文地址:https://www.cnblogs.com/ydnhaha/p/10307555.html
Copyright © 2020-2023  润新知