• 值得一做》关于数学与递推 BZOJ1002 (BZOJ第一页计划)(normal+)


      什么都不说先甩题目

    Description

      轮状病毒有很多变种,所有轮状病毒的变种都是从一个轮状基产生的。一个N轮状基由圆环上N个不同的基原子
    和圆心处一个核原子构成的,2个原子之间的边表示这2个原子之间的信息通道。如下图所示

      N轮状病毒的产生规律是在一个N轮状基中删去若干条边,使得各原子之间有唯一的信息通道,例如共有16个不
    同的3轮状病毒,如下图所示

      现给定n(N<=100),编程计算有多少个不同的n轮状病毒

     

    Input

      第一行有1个正整数n

    Output

      计算出的不同的n轮状病毒数输出

    Sample Input

    3

    Sample Output

    16

      这道题其实思路应该是生成树计数问题,但是很明显的,本题给出的数据范围对于一般使用的Matrix-Tree定理(Kirchhoff矩阵-树定理)来说数据范围有点大,所以在这里Matrix-Tree只作为暴力算法,正解得出的方法是用奇怪的递推式。

      首先来讲讲Matrix-tree,具体方法是这样:

      一,首先得出一个点的度的矩阵A,定义为:对于当前矩阵A[i][j]来说,只有在当前i=j的情况下,A[i][j]为第i个点的度数,其他点为0;

      二,得出一个关于边的矩阵B,定义为:对于当前的矩阵B[i][j]来说,当i与j相连的情况下,B[i][j]为1,其他点为0;

      最后得出一个最终矩阵C,对于C的定义为:C[i][j]=A[i][j] - B[i][j];

      我们在最后的计算前要对矩阵C做一件玄学的事情:以一个对角线数字作为关键点,消掉该关键带点所在横行于纵行所有点(包括自己),把剩下的点再拼成矩阵C(事关玄学);

      接下来就很简单了,把新矩阵C当做一组线性方程,然后用高斯消元对C来求解(只需要把由对角线切开的任意一个数字三角上的数全消为0即可),然后把对角线上的数字全部相乘,得出解;

      贴出以这种方法写的n<20的暴力

     1 #include<stdio.h>
     2 double mp[110][110];
     3 int n;
     4 int main()
     5 {
     6     scanf("%d",&n);
     7     if(n==1){printf("1");return 0;}//来组特判 
     8     if(n==2){printf("5");return 0;}
     9     mp[1][1]=3,mp[1][n]=-1,mp[1][2]=-1,mp[n][n]=3,mp[n][1]=-1,mp[n][n-1]=-1;
    10     for(int i=2;i<n;i++)mp[i][i-1]=mp[i][i+1]=-1,mp[i][i]=3;//以下是建立矩阵的过程 
    11     for(int i=2;i<=n;++i)//对于这道题,把中间的点看做要消掉的点,建矩阵方法因人而异 
    12     {
    13         for(int j=1;j<i;++j)
    14         {
    15             double shit=(-mp[i][j])/mp[j][j];
    16             for(int k=j;k<=n;++k)
    17             mp[i][k]+=mp[j][k]*shit;
    18         }
    19     }
    20     double ans=1;
    21     for(int i=1;i<=n;i++)
    22         ans*=mp[i][i];
    23     printf("%d",(int)(ans+0.5));//四舍五入 
    24     return 0;
    25 }
    Matrix-tree

      但是这样并不能A,所以我们要想一种更优的解,

      根据对打表数据的判断,可以得出g[i]=3*g[i-1]-g[i-2]+2的神奇结论;

      这个公式好像要依靠对于数论的理解来分析(对于新加入的点对于全图的关系),得出递推式。

      贴出正解代码

     1 #include<stdio.h>
     2 struct shit{
     3     int a[1000],len;
     4 }g[110];
     5 int n;
     6 shit c(shit x,int y)
     7 {
     8     for(int i=1;i<=x.len;i++)x.a[i]*=y;
     9     for(int i=1;i<=x.len;i++)
    10     {
    11         x.a[i+1]+=x.a[i]/10;
    12         x.a[i]%=10;
    13     }
    14     if(x.a[x.len+1])x.len++;
    15     return x;
    16 }
    17 shit j(shit x,shit y)
    18 {
    19     x.a[1]+=2;
    20     int s=x.len;
    21     shit z;
    22     for(int i=1;i<=x.len;i++)
    23     {
    24         if(x.a[i]<y.a[i])x.a[i+1]--,x.a[i]+=10;
    25         x.a[i]=x.a[i]-y.a[i];
    26     }
    27     while(x.a[x.len]==0)x.len--;
    28     return x;
    29 }
    30 int main()
    31 {
    32     scanf("%d",&n);
    33     g[1].a[1]=1,g[1].len=1;
    34     g[2].a[1]=5,g[2].len=1;
    35     for(int i=3;i<=n;++i)
    36         g[i]=j(c(g[i-1],3),g[i-2]);
    37     for(int i=g[n].len;i>=1;i--)printf("%d",g[n].a[i]);
    38     return 0;
    39     
    40 } 
    View Code

    另外还有一种思路提供参考

    【规律】这里是1--15的打表情况:1 5 16 45 121 320 841 2205 5776 15125 39601 103680 271441 710645 1860496。很快先发现一个规律:第1、3、5、7位是平方数,2、4、6、8位除以5后也是平方数。

        然后再整理:1*1 5*1*1 4*4 5*3*3 11*11 5*8*8 29*29 5*21*21 76*76 5*55*55 199*199 5*144*144 521*521。看着奇数位1,3,8,21,55。。。。。。灵光一现:这不是斐波那契的一半吗:1,2,3,5,8,13,21,24,55.。。。。。另外一个也能表示成类似的相加的数列:

    奇数位:1 3 4 7 11 18 29 76

    偶数位:1 2 3 5 8 13 21 34 55

    主要结论来自于:http://blog.csdn.net/jiangshibiao/article/details/22645557

    然后贴出以这种方式A的神犇的代码

     1 #include<cstdio>
     2 #include<cstring>
     3 using namespace std;
     4 const int size=51;                 //这里的位数卡着n=100的情况,为了加速。
     5 struct arr{int num,p[size];}a,b,c;
     6 int i,n,j;
     7 arr add(arr a,arr b)
     8 {
     9   arr c;memset(c.p,0,sizeof(c.p));
    10   c.num=a.num>b.num?a.num:b.num;
    11   for (int i=1;i<=c.num;i++)
    12     c.p[i]=a.p[i]+b.p[i];
    13   for (int i=1;i<=c.num;i++)
    14     c.p[i+1]+=c.p[i]/10,c.p[i]%=10;
    15   if (c.p[c.num+1]) c.num++;
    16   return c;
    17 }
    18 arr chen(arr a,arr b)
    19 {
    20   arr c;memset(c.p,0,sizeof(c.p));
    21   for (int i=1;i<=a.num;i++)
    22     for (int j=1;j<=b.num;j++)
    23       c.p[i+j-1]+=a.p[i]*b.p[j];
    24   c.num=a.num+b.num-1;
    25   for (int i=1;i<=c.num;i++)
    26     c.p[i+1]+=c.p[i]/10,c.p[i]%=10;
    27   while (c.p[c.num+1])
    28   {
    29     c.num++;c.p[c.num+1]+=c.p[c.num]/10;c.p[c.num]%=10;
    30   }
    31   return c;
    32 }
    33 int main()
    34 {
    35   scanf("%d",&n);
    36   switch (n) 
    37   {
    38     case 0:{printf("0");return 0;}
    39     case 1:{printf("1");return 0;}
    40     case 2:{printf("5");return 0;}
    41   }
    42   if (n%2==0)
    43   {
    44     a.p[1]=1;b.p[1]=2;a.num=1;b.num=1;
    45     for (i=4;i<=n;i++)
    46     {
    47       c=add(a,b);
    48       a.num=b.num;for (j=1;j<=a.num;j++) a.p[j]=b.p[j];
    49       b.num=c.num;for (j=1;j<=b.num;j++) b.p[j]=c.p[j];
    50     }
    51     c=chen(c,c);
    52     memset(a.p,0,sizeof(a.p));a.p[1]=5;a.num=1;c=chen(c,a);
    53     for (i=c.num;i>0;i--)
    54       printf("%d",c.p[i]);
    55   }
    56   else
    57   {
    58     a.p[1]=1;b.p[1]=3;a.num=1;b.num=1;
    59     for (i=3;i<=n;i++)
    60     {
    61       c=add(a,b);
    62       a.num=b.num;for (j=1;j<=a.num;j++) a.p[j]=b.p[j];
    63       b.num=c.num;for (j=1;j<=b.num;j++) b.p[j]=c.p[j];
    64     }
    65     c=chen(c,c);
    66     for (i=c.num;i>0;i--)
    67       printf("%d",c.p[i]);
    68   }
    69   return 0;
    70 }
    View Code
  • 相关阅读:
    [原]获取openstack-pike安装包
    [原]Failed connect to mirrors.cloud.aliyuncs.com:80; Connection refused
    [原]shell批量文件增删改前后缀
    [原]CentOS 7 chrony 笔记
    [原]Docker-issue(2) http: server gave HTTP response to HTTPS client
    [原]Docker-issue(1) image name 显示为 <none>
    [原]Django(1)----Django-setting中的STATIC_URL 和STATIC_ROOT 和STATICFILES_DIRS 的区别
    [原]Django-issue(1)---postgresql数据库连接密码错误
    [转]50个极好的bootstrap 后台框架主题下载
    [原]eclipse + pydev :Error in sitecustomize; set PYTHONVERBOSE for tracaeback: KeyError: 'sitecustomize'
  • 原文地址:https://www.cnblogs.com/PencilWang/p/5907796.html
Copyright © 2020-2023  润新知