Codeforces #341 div 2 E. Wet Shark and Blocks(矩阵快速幂)
2016-02-25 21:48
531 查看
题目链接:
http://codeforces.com/contest/621/problem/E
题目大意:
给b个block,每个block有n个数,现在从每个block里面选一个数然后首尾串起来组成一个新的数,对这个数取模x以后,问结果等于k的种类数。
范围:
2 ≤ n ≤ 50 000, 1 ≤ b ≤ 109, 0 ≤ k < x ≤ 100, x ≥ 2
思路:
首先可以想到用dp,设dp[i][j]为选到第i个block时候取模为j的种类数,此时有:dp[i+1][(j*10+k)%mod]+=dp[i][j]*num[k]。(1<=k<=9)
但是这里的b很大,关系又是线性的,所以想到用矩阵快速幂。
我们可以构造出一个矩阵m[i][j],表示从i到j的种类数。
初始情况下,有一个dp[x]={1,0,0,……}。
那么只看一个block的情况的时候,就有dp[x]*m[x][x],此时获得的行矩阵就是只选一个的时候的情况数。
2个的时候,就是dp[x]*m[x][x]*m[x][x]。
……
这样就是dp[x]*(m[x][x])^n。
而初始的时候的m[x][x],我们可以知道m[i][(j*10+k)%x]+=num[j]。
代码:
http://codeforces.com/contest/621/problem/E
题目大意:
给b个block,每个block有n个数,现在从每个block里面选一个数然后首尾串起来组成一个新的数,对这个数取模x以后,问结果等于k的种类数。
范围:
2 ≤ n ≤ 50 000, 1 ≤ b ≤ 109, 0 ≤ k < x ≤ 100, x ≥ 2
思路:
首先可以想到用dp,设dp[i][j]为选到第i个block时候取模为j的种类数,此时有:dp[i+1][(j*10+k)%mod]+=dp[i][j]*num[k]。(1<=k<=9)
但是这里的b很大,关系又是线性的,所以想到用矩阵快速幂。
我们可以构造出一个矩阵m[i][j],表示从i到j的种类数。
初始情况下,有一个dp[x]={1,0,0,……}。
那么只看一个block的情况的时候,就有dp[x]*m[x][x],此时获得的行矩阵就是只选一个的时候的情况数。
2个的时候,就是dp[x]*m[x][x]*m[x][x]。
……
这样就是dp[x]*(m[x][x])^n。
而初始的时候的m[x][x],我们可以知道m[i][(j*10+k)%x]+=num[j]。
代码:
#include<stdio.h> #include<string.h> #include<algorithm> #include<iostream> #define mod 1000000007 #define ll __int64 using namespace std; struct Mat{ ll mat[101][101]; void init(){ memset(mat,0,sizeof(mat)); } }; int M,cnt[11],x; Mat operator * (Mat a, Mat b) { Mat c; memset(c.mat, 0, sizeof(c.mat)); int i, j, k; for(k = 0; k < M; ++k) { for(i = 0; i < M; ++i) { for(j = 0; j < M; ++j) { c.mat[i][j] += (a.mat[i][k] * b.mat[k][j]); c.mat[i][j]=(c.mat[i][j]+mod)%mod; } } } return c; } Mat operator ^ (Mat a, ll k) { Mat c; int i, j; for(i = 0; i < M; ++i) for(j = 0; j < M; ++j) c.mat[i][j] = (i == j); //初始化为单位矩阵 for(; k; k >>= 1) { if(k&1) c = c*a; a = a*a; } return c; } int main() { Mat a1,a2; int n,i,j,k,K,b,a[50005]; while(~(scanf("%d",&n))) { memset(cnt,0,sizeof(cnt)); a2.init(); scanf("%d%d%d",&b,&K,&x); for(i=1;i<=n;i++) { scanf("%d",&a[i]); cnt[a[i]]++; } M=x; for(i=0;i<x;i++) for(j=0;j<=9;j++) { a2.mat[i][(i*10+j)%x]+=cnt[j]; } a1.init(); a1.mat[0][0]=1; a2=a2^b; a1=a1*a2; printf("%I64d\n",a1.mat[0][K]); } }
相关文章推荐
- 一些常用css技巧的为什么(二)我所理解的line-height
- PB中treeview 的checkboxes用法完整版
- VS与Matlab混合编译 - mexw64
- 【技术】CocoaPods检测需要更新的命令
- 一起talk C栗子吧(第一百二十三回:C语言实例--显示变量和函数的地址)
- qt中int与string的相互转换
- 面向对象程序设计
- IielgnairTs'lacsaP.119
- 使用Zxing来实现二维码扫描
- 透视变换-鸟瞰图
- STM32 IAP在线升级教学
- Python 3 之 lambda匿名函数详解
- C# 枚举在项目中使用心得
- 练习: 水仙花数、百钱白鸡、百马百担
- java经典问题
- ImageView切换两种状态下的模式
- wex5的组件简介
- Android SearchView的使用
- python装饰器的学习笔记一
- 七牛---Python_SDK_Demos