• 【jzoj5335】早苗


    题目描述
           Sanae准备对大结界进行一次连续n天的风祭。Sanae每天可以召唤一种神风。她一共有m种神风可以召唤,但是如果有连续m天刮了m种不同的神风,环境就会遭到破坏。现在,Sanae想知道这n天她有多少种召唤神风的方案。
           由于答案可能很大,所以你只需要告诉她方案数对1000000007取模的结果即可。

    输入
           两个正整数n,m,分别代表风祭的天数和Sanae能召唤的风的种数。

    输出
           一个整数,为答案对1000000007取模的结果。

    样例输入
    3 3

    样例输出
    21

    数据范围
           对于8%的数据,m=2
           对于另16%的数据,n<=10,m<=4
           对于48%的数据,n<=100000,m<=10
           对于80%的数据,n<=100000,2<=m<=100
           对于100%的数据,2<=m<=100,m<=n<=10^16

    思路

           题目大意:求用1~m组成有n个数的序列,任意连续m个数不能互不相同的方案数

           ???任意连续m个数不能互不相同?如果我第i个放了数字j,那我前面必须放哪些数?i和i-1有什么关系?任意连续m个数不能互不相同的情况太多了吧……
           好像不管怎么想都得用减法啊……

    多试试逆向

           设f[i]是用了i个数的合法方案数,h[i]是用了i个数的不合法方案数。
           f[i]+h[i]=mn
        
           求不出f[i],那我们来求h[i]吧~
           emmmmmmm,考虑h[i]和h[i-1]的关系,可以看出h[i]必定包含h[i-1]*m(意思是最后一位随便放,比f好多了),也就是h[i]=h[i-1]*m+g[i],其中g[i]为加上第i数后新出现的不合法方案数。显然,g[i]的最后m个数是个全排列,也就是g[i]包含了m!*f[i-m]。
           然而,我们这样算会算重。
           “g[i]为加上第i数后新出现的不合法方案数。”,新出现,也就是只有i-m+1~i是全排列,那么i-m~i-1,i-m-1~i-2……都不能是全排列。m!*f[i-m]不能保证这点。
           例如:m=5,你想算g[9],5 3 2 3 1 5 4 2 3中,f[4]确实包含5 3 2 3这个方案,但g[9]中不包含5 3 2 3 1 5 4 2 3,因为5 3 2 3 1 5 4早就已经不合法了。
           但我们可以去重啊。
           对于m!*f[i-m]中的每一个算重的序列,我们找到这个序列第一次出现全排列的位置假设为i-j-m+1~i-j(1<=j<=m-1),那么i-j-m+1~i-j是全排列而i-m+1~i也是全排列,那么i-j+1~i也是有j个元素的全排列(数字不一定正好是1~j,但肯定是j个元素)。那么我们就要减掉j!*g[i-j]个方案数.
           总递推式:g[i]=m!*f[i-m]-$sum _limits{j=1}^{m-1}j!ast gleft[ i-j ight]$
                    =m!*(mi-m-h[i-m])-$sum _limits{j=1}^{m-1}j!ast gleft[ i-j ight]$
           其中h[i-m]=h[i-m-1]*m+g[i-m].

           目前的复杂度为O(n*m),80分。

    优化
           递推式的主体可以看作是n,而n的范围n<=10^16.
           妥妥的矩阵乘法优化。
           根据递推式里,与i有关的有mi-m,h[i-m],g[i-j],所以我们把矩阵转移方向定为:

      总转移:


           转移矩阵就让大家自己思考啦。

    代码:

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstdlib>
     4 #include <cmath>
     5 #include <algorithm>
     6 #include <cstring>
     7 #include <string>
     8 #include <queue>
     9 #define fo(p,q,r) for(p=q;p<=r;++p)
    10 #define fow(p,q,r) for(p=q;p>=r;--p)
    11 #define arclr(p,q) memset(p,q,sizeof(p))
    12 using namespace std;
    13 typedef long long LL;
    14 
    15 const LL mo=1000000007;
    16 
    17 LL mr[105][105][2],temp[105][105],st[105],en[105],ans;
    18 
    19 LL jc[105],n,m,i,j,cnt;
    20 
    21 void mul(LL p,LL q,LL r)
    22 {
    23     LL i1,j1,k1;
    24     arclr(temp,0);
    25     fo(i1,1,m+1)
    26         fo(j1,1,m+1)
    27             fo(k1,1,m+1)
    28             temp[i1][j1]=(temp[i1][j1]+((mr[i1][k1][p]*mr[k1][j1][q])%mo))%mo;
    29     fo(i1,1,m+1)
    30         fo(j1,1,m+1)
    31         mr[i1][j1][r]=temp[i1][j1];
    32 }
    33 
    34 void build()
    35 {
    36     mr[1][1][0]=m;
    37     fo(i,2,m-1)
    38         mr[i][i+1][0]=1;
    39     mr[m][m+1][0]=(2*mo-jc[m])%mo;
    40     mr[m][1][0]=jc[m];
    41     fo(i,2,m) mr[m][i][0]=(2*mo-jc[m-i+1])%mo;
    42     mr[m+1][2][0]=1; mr[m+1][m+1][0]=m;
    43         
    44     fo(i,1,m+1)
    45         mr[i][i][1]=1;
    46 }
    47 
    48 void mi(LL p)
    49 {
    50     LL i1=p; 
    51     while (i1>0)
    52     {
    53         if (i1&1) mul(1,0,1);
    54         mul(0,0,0);
    55         i1>>=1;
    56     }
    57 }
    58 
    59 int main()
    60 {
    61     scanf("%lld%lld",&n,&m);
    62     
    63     jc[0]=1; 
    64     fo(i,1,m) jc[i]=(jc[i-1]*i)%mo;
    65     
    66     st[1]=1; 
    67     fo(i,2,m+1) st[i]=0;
    68     
    69     build();
    70 
    71     fo(i,1,m+1)
    72     {
    73         fo(j,1,m+1) printf("%lld ",mr[i][j][0]);
    74         printf("
    ");
    75     }
    76     
    77     mi(n);
    78     
    79     arclr(en,0);
    80     fo(i,1,m+1) 
    81         fo(j,1,m+1) 
    82             en[i]=(en[i]+((mr[i][j][1]*st[j])%mo))%mo;
    83     
    84     ans=(en[1]-en[m+1]+mo)%mo;
    85     printf("%lld
    ",ans);
    86 }
    矩阵快速幂
  • 相关阅读:
    .NET的DTO映射工具AutoMapper
    使用TeamCity对项目进行可持续集成管理
    SpecFlow
    重构--改善既有代码的设计
    EntityFramework 7 开发纪录
    Solr索引
    DDD分层架构之值对象(层超类型篇)
    C#异步Socket示例
    Cnblogs API
    白鸦三次创业反思:公司遇问题 怎么走都对(转)
  • 原文地址:https://www.cnblogs.com/Krain428571/p/7426787.html
Copyright © 2020-2023  润新知