省队集训DAY6
来源:互联网 发布:网络购物狂欢节 编辑:程序博客网 时间:2024/05/16 06:43
T1
题解
f[i]表示以字符i结尾的字符串的个数。
那么现在加入一个字符产生的贡献就是
考虑这么做会不会产生相同的串?假设acbb,考虑插入第一个b的影响会形成ab,cb,acb.那么插入第二个b会形成abb,cbb,acbb发现这些都是新产生的不会与之前的相同,而且不会影响到a,c结尾的字符串。
那么每次转移实际上是乘上了一个对角线为1,某一列为1为1的矩阵。
我们可以维护矩阵的前缀积,和逆矩阵的前缀积。
那么对于每次询问都可以看成是两个矩阵相乘。
因为矩阵是没有交换率的,所以正矩阵维护成
对于逆矩阵,我们要保证
如何求一个矩阵的逆矩阵?
什么是逆矩阵?
首先将逆矩阵赋值为单位矩阵,然后对A进行高斯消元,将A矩阵变成单位矩阵,变换过程中对A矩阵的所有操作都在逆矩阵中同等实现。做完后的逆矩阵即为所求。
如果最后无法消成单位矩阵,那么说明该矩阵不存在逆矩阵。
代码
#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<cmath>#define N 10#define p 1000000007#define LL long long using namespace std;struct data{ LL a[N+3][N+3];}base[N+3],inv[N+3],ans,sum[100003],sinv[100003];int n,m; char s[100003];data mul(data a,data b){ data c; for (int i=1;i<=N;i++) for (int j=1;j<=N;j++) { c.a[i][j]=0; for (int k=1;k<=N;k++) c.a[i][j]=c.a[i][j]+a.a[i][k]*b.a[k][j]; c.a[i][j]%=p; } return c;}LL quickpow(LL num,int x){ LL ans=1,base=num%p; while (x) { if (x&1) ans=ans*base%p; x>>=1; base=base*base%p; } return ans;}void guass(data a,data &inv){ for (int i=1;i<=N;i++) inv.a[i][i]=1; for (int i=1;i<=N;i++) { int num=i; for (int j=i+1;j<=N;j++) if (abs(a.a[j][i])>abs(a.a[num][i])) num=j; if (num!=i) { for (int j=1;j<=N;j++) swap(a.a[i][j],a.a[num][j]), swap(inv.a[i][j],inv.a[num][j]); } LL t=quickpow(a.a[i][i],p-2); for (int j=1;j<=N;j++){ a.a[i][j]=a.a[i][j]*t%p; inv.a[i][j]=inv.a[i][j]*t%p; } for (int j=1;j<=N;j++) if (i!=j&&a.a[j][i]) { t=a.a[j][i]; for (int k=1;k<=N;k++){ a.a[j][k]=(a.a[j][k]-a.a[i][k]*t%p)%p; inv.a[j][k]=(inv.a[j][k]-inv.a[i][k]*t%p)%p; } } }}int main(){ freopen("sub.in","r",stdin); freopen("sub.out","w",stdout); scanf("%s",s+1); n=strlen(s+1); for (int t=1;t<=9;t++) { for (int i=1;i<=N;i++) base[t].a[i][i]=1; for (int i=1;i<=N;i++) base[t].a[i][t+1]=1; guass(base[t],inv[t]); } ans.a[1][1]=1; for (int i=1;i<=N;i++) sinv[0].a[i][i]=1; sum[1]=base[s[1]-'a'+1]; sinv[1]=inv[s[1]-'a'+1]; for (int i=2;i<=n;i++) sum[i]=mul(sum[i-1],base[s[i]-'a'+1]), sinv[i]=mul(inv[s[i]-'a'+1],sinv[i-1]); scanf("%d",&m); for (int i=1;i<=m;i++) { int l,r; scanf("%d%d",&l,&r); LL ck=0; for (int j=1;j<=N;j++) for (int k=1;k<=N;k++) ck=(ck+sinv[l-1].a[1][j]*sum[r].a[j][k]%p)%p; printf("%I64d\n",(ck+p-1)%p); }}
阅读全文
0 0
- 省队集训DAY6
- 省队集训Round3 DAY6
- 湖南集训Day6
- ACM集训day6
- 寒假集训 day6
- 沈阳集训day6
- 北京集训DAY6
- 2015湖南省队集训DAY6——B题(BZOJ4179)
- 5月集训Day6考试
- [莫队维护DP] LOJ#6074. 「2017 山东一轮集训 Day6」子序列
- 【泉州一中国庆集训day6】String
- 2017 暑假艾教集训 day6
- 集训Day6 T1 次方的运算
- 省队集训 water
- 省队集训DAY2
- 省队集训DAY3
- 省队集训DAY4
- 省队集训DAY5
- 获得RGB图像三种颜色分量并进行条件筛选
- Rasterio 安装
- 【10.6】c++ primer plus 课后编程答案
- 关于private继承
- 《算法分析与设计》Week 16
- 省队集训DAY6
- TB
- Android常用控件(二)
- Ubuntu中最简单好用截图工具shutter安装
- 【10.7】c++ primer plus 课后编程答案
- 约瑟夫环问题(二):(难度:2颗星)
- Java数组创建
- 解决卸载或者安装程序失败的问题,提示:错误 1402。无法打开键UNKNOWN\Components\xxx
- POJ 1738 An old Stone Game 笔记