zrt中文题

orzzrt....

题意:给n个点n条边,问能形成几个无向连通图
公式:ans=Σ(k=3~n){[n^(n-k)]* (n-1)!/2(n-k)!}
推导:ans=Σ(k=3~n)(f(n,k)*h(k))
f(n,k)表示能形成的森林个数,h(k)表示能形成的环的个数
h(k)=n!/2n n!:排列的种类 n!/n:去重(123,231,312) (n!/n)/2:去重(123,321)
∴h(k)=(k-1)!/2
设g(n,k)=f(n,k)*(n-k)! (边有编号时森林的个数)
=n(n-1)n(n-2)*...*n*k
=n^(n-k)*(n-1)!/(k-1)!
∴f(n,k)=n^(n-k)*(n-1)!/[(k-1)!*(n-k)!]
∴ans=Σ(k=3~n){[n^(n-k)]* (n-1)!/2(n-k)!}
需要用到高精度

#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<string>
#define MAX 10010
using namespace std;
char ans[MAX],sum[MAX];

int bigchenfa(int *sum2,int *a,int *b,int lsum,int la,int lb) 
{
    int i,j,k ; 
    memset(sum2,0,sizeof(sum2)); 
    lsum=0; 
    for(i=1;i<=la;i++) 
    for(j=1,lsum=i-1;j<=lb;j++) 
    sum2[++lsum]+=b[j]*a[i]; 
    for(i=1;i<=lsum;i++)
    if(sum2[i]>=10) 
    {
        if(sum2[lsum]>=10) 
        lsum++; 
        sum2[i+1]+=sum2[i] / 10 ; 
        sum2[i]%=10 ; 
    }
    return lsum ; 
}

void multiply(int ac)
{
    int a[MAX]={0},b[MAX]={0},sum2[MAX*2]={0} ; 
      int la=0,lb=1,lsum=0; 
      int i,j;
      int b1=ac;
      la=strlen(ans);  
      for(int i=1,j=la-1;i<=la;i++,j--) a[i]=ans[j]-'0'; 
      while(b1>0)
      {
        b[lb]=b1%10;
        lb++;
        b1/=10;    
    }
    lb-=1;
      lsum = bigchenfa(sum2,a,b,lsum,la,lb) ; 
      memset(ans,0,sizeof(ans));
      for(i=lsum,j=0;i>=1;i--,j++) ans[j]=sum2[i]+'0'; 
}

int sum1[MAX],ans1[MAX];
void add()
{
    int lena,lenb,len;
    lena=strlen(sum);
    lenb=strlen(ans);
    len=max(lena,lenb);
    memset(sum1,0,sizeof(sum1));
    memset(ans1,0,sizeof(ans1));
    for(int i=lena-1,j=0;i>=0;i--,j++)sum1[j]=sum[i]-'0';
    for(int i=lenb-1,j=0;i>=0;i--,j++)ans1[j]=ans[i]-'0';
    for(int i=0;i<len;i++)
    {
        if(sum1[i]+ans1[i]>=10) sum1[i+1]++;
        sum1[i]=(sum1[i]+ans1[i])%10;
    }
    if(sum1[len]!=0)len++;
    memset(sum,0,sizeof(sum));
    for(int i=len-1,j=0;i>=0;i--,j++)
    {
        sum[j]=sum1[i]+'0';
    }
}
void divide()
{
    int a[MAX]={0},c[MAX]={0};
    int i,k,d=0; 
    k=strlen(sum); 
    for(i=0;i<k;i++)
        a[i]=sum[k-i-1] - '0';
    for(i=k-1;i>=0;i--) 
    {
        d=d*10+a[i]; 
        c[i]=d/2;
        d=d%2; 
    }
    while(c[k-1]==0&&k>1) k--; 
    for(i=k-1;i>=0;i--) cout<<c[i];
}

int main()
{
    int n;
    cin>>n;
    for(int k=3;k<=n;k++)
    {
        memset(ans,0,sizeof(ans));
        ans[0]='1';
        for(int i=1;i<=n-k;i++)
        {
            multiply(n);    
        }
        for(int i=n-k+1;i<=n-1;i++)
        {
            multiply(i);    
        }
        add();
    }
    divide();
    return 0;
} 
原文地址:https://www.cnblogs.com/xiaoxubi/p/6233609.html