• hdu2294:Pendant


    T<=10组数据问K<=30种珠子每种n<=1e9串成1~n长度的序列共有多少种,mod1234567891。

    方程没想到。矩阵不会推。很好。

    f[i][j]--长度i,j种珠子方案数,f[i][j]=f[i-1][j]*j(放个旧的)+f[i-1][j-1]+(K-(j-1))(放个新的)

    n太大,推不动。由于f[i-1]->f[i],考虑矩乘优化。设递推用的矩阵为A。F[i]表示f[i][1]~f[i][k]。

    方法一:f加多一个数表示ans,初始化{0,k,0,0,……},那个k是f[1]。A如下:直接乘即可。注意初始化,以及最后一步谁乘谁搞清楚。

    方法二:最终答案为F[1][k]+F[2][k]+……+F[n][k],也就是F[1]+F[2]+……+F[n]的第K项,F[i]=A*F[i-1]=A^(i-1)*F[1],所以问题就是(E+A+A^2+……+A^n-1)*F[1]的第K项,前面那坨东西:

    方法(1):G[i]=(E+A+A^2+......+A^i),E是单位矩阵。G[i奇]=G[i-1]*A^i,G[i偶]=G[i/2]+A^(i/2)*G[i/2],这样G[n-1]可以dfs在log时间内求,而每次要一个快速幂求A^i,复杂度k^3log2n,虽能过题但不优秀。

    方法(2):(来自yyl大爷)把所有的构造往二次幂想。把n-1二进制表示出来,比如10110,新建个H[i]=(E+A+A^2+.....+A^i-1)注意是i-1,那么H[n]=H[10000]*A^110+H[100]*A^10+H[10]*E,也就是如果能求出H[2^i],那么是可以扫一遍n的二进制位把H[n]求出来的,边扫边更新A的若干次方(遇到1时)。而H[2^i]=H[2^(i-1)]*(A^(2^(i-1))+E),A^(2^i)又是可以算的。算A^(2^i),H[2^i],以及最后枚举二进制位,都是可以k^3logn求出来的。

    以下方法一。

     1 #include<stdio.h>
     2 #include<string.h>
     3 #include<algorithm>
     4 #include<math.h>
     5 //#include<iostream>
     6 using namespace std;
     7 
     8 int n,K,T;
     9 #define maxn 111
    10 #define LL long long
    11 typedef LL mat[maxn][maxn];
    12 mat base,ans,f;
    13 const int mod=1234567891;
    14 void mul(mat a,mat b,mat &ans)
    15 {
    16     mat t;
    17     memset(t,0,sizeof(t));
    18     for (int i=0;i<=n;i++)
    19         for (int j=0;j<=n;j++)
    20             for (int k=0;k<=n;k++)
    21                 t[i][j]=(t[i][j]+a[i][k]*b[k][j]%mod)%mod;
    22     for (int i=0;i<=n;i++)
    23         for (int j=0;j<=n;j++)
    24             ans[i][j]=t[i][j];
    25 }
    26 int main()
    27 {
    28     scanf("%d",&T);
    29     while (T--)
    30     {
    31         scanf("%d%d",&K,&n);
    32         if (K<n) {puts("0");continue;}
    33         memset(base,0,sizeof(base));
    34         base[0][0]=base[0][n]=1;
    35         base[1][1]=1;
    36         for (int i=2;i<=n;i++)
    37         {
    38             base[i][i-1]=n-i+1;
    39             base[i][i]=i;
    40         }
    41         memset(ans,0,sizeof(ans));
    42         for (int i=0;i<=n;i++) ans[i][i]=1;
    43         while (K)
    44         {
    45             if (K&1) mul(ans,base,ans);
    46             mul(base,base,base);
    47             K>>=1;
    48         }
    49         memset(f,0,sizeof(f));
    50         f[1][0]=n;
    51         mul(ans,f,f);
    52         printf("%lld
    ",f[0][0]);
    53     }
    54     return 0;
    55 }
    View Code
  • 相关阅读:
    成功的软件开发过程 迭代,进化和敏捷
    将动态aspx页面转换成为静态html页面的几种方法
    大社区型网站的架构总结之如何标示用户在使用哪个功能程序篇(草稿)
    如果你觉得能做项目经理,就不要屈就自己去做普通程序员
    软件测试人的职业发展
    软件测试工程师,应该掌握的技能
    内存分配的字节对齐
    约瑟夫问题循环链表
    Linux字符设备驱动结构
    抵制日货(中国人一年购买日本货的钱,足够维持小鬼子2年半的军费)
  • 原文地址:https://www.cnblogs.com/Blue233333/p/7447723.html
Copyright © 2020-2023  润新知