BNUOJ 34985 Elegant String 2014北京邀请赛E题 矩阵快速幂

题目链接:http://acm.bnu.edu.cn/bnuoj/problem_show.php?pid=34985

题目大意:问n长度的串用0~k的数字去填,有多少个串保证任意子串中不包含0~k的某一个全排列

邀请赛上A的较多的一道题,比赛的时候死活想不出,回来之后突然就想通了,简直..... = =!

解题思路:

对于所有串我们都只考虑末尾最多有多少位能构成全排列的一部分(用l来表示),即最多有多少位不重复的数字出现,将问题转化为求末尾最多有k位能构成全排列的串的总数量

假设k为5,有一个串……0023,不难发现l=3

我们以这个串出发在之后添上数字,假如我们添的是0、2、3中的一个:

  0: ……00230 (l=3)

  2: ……00232 (l=2)

  3: ……00233 (l=1)

假如是l长度中没有出现过的数字

  则构成新串 ……00231 ……00234  ……00235 l=4

最后可以得到规律:总长度为n串中 l=m的串的数量 x1 得到 总长度为n+1的串中 l=(1,2,……,m)的串

         总长度为n串中 l=m的串的数量 x(k-m+2) 得到 总长度为n+1的串中 l=m+1的串

用mar[i][j]来表示由l=j的串得到l=i的串所以

mar可以表示为(以k=5为例)

1  1  1  1  1

5  1  1  1  1

0  4  1  1  1

0  0  3  1  1

0  0  0  2  1

通过该矩阵我们可以由长度为n的串数量可以推出长度为n+1的串的数量:

于是我们可以通过长度1的串最终得到总长度为n的串,  n=1时只有l最多为1 总数为 k+1

快速幂求得该矩阵的(n-1)次幂,该矩阵的第一列相加乘(k+1)即为最终结果

 1 #include <cmath>
 2 #include <cstdio>
 3 #include <cstring>
 4 #include <iostream>
 5 #include <algorithm>
 6 using namespace std;
 7 #define FFF 20140518
 8 struct node{
 9     long long mar[15][15];
10 }sor;
11 void init(int k)
12 {
13     memset(sor.mar,0,sizeof(sor.mar));
14     for(int i=1;i<=k;i++)
15     {
16         for(int j=i;j<=k;j++)
17         {
18             sor.mar[i][j]=1;
19         }
20         if(i>1)
21         {
22             sor.mar[i][i-1]=k-i+2;
23         }
24     }
25 }
26 node marMulti(node a,node b,int k)
27 {
28     node ret;
29     memset(ret.mar,0,sizeof(ret.mar));
30     for(int i=1;i<=k;i++)
31     {
32         for(int j=1;j<=k;j++)
33         {
34             for(int l=1;l<=k;l++)
35             {
36                 ret.mar[i][j]+=(a.mar[i][l]*b.mar[l][j])%FFF;
37                 ret.mar[i][j]%=FFF;
38             }
39         }
40     }
41     return ret;
42 }
43 node matrixPow(long long x,int k)
44 {
45     node now=sor;
46     node ret;
47     memset(ret.mar,0,sizeof(ret.mar));
48     for(int i=1;i<=k;i++)
49         ret.mar[i][i]=1;
50     while(x)
51     {
52         if(x%2==1)
53             ret=marMulti(now,ret,k);
54         x/=2;
55         now=marMulti(now,now,k);
56     }
57     return ret;
58 }
59 void print(node sor,int k)
60 {
61     for(int i=1;i<=k;i++)
62     {
63         for(int j=1;j<=k;j++)
64         {
65             cout<<sor.mar[i][j]<<' ';
66         }
67         cout<<endl;
68     }
69 }
70 int main()
71 {
72     int keng,k,Case=1;
73     long long n;
74     scanf("%d",&keng);
75     while(keng--)
76     {
77         scanf("%lld%d",&n,&k);
78         init(k);
79         node ret=matrixPow(n-1,k);
80         int ans=0;
81         // print(sor,k);
82         // print(ret,k);
83         for(int i=1;i<=k;i++)
84         {
85             ans+=(ret.mar[i][1]*(k+1))%FFF;
86             ans%=FFF;
87         }
88         printf("Case #%d: %d\n",Case++,ans);
89     }
90     return 0;
91 }
View Code

 

posted @ 2014-05-27 12:04  飞火扑蛾  阅读(520)  评论(0编辑  收藏  举报