[JZOJ5132][SDOI省队集训2017]子序列
来源:互联网 发布:雨人软件改名 编辑:程序博客网 时间:2024/05/29 19:36
题目大意
字符集为9的字符串。
若干次询问区间本质不同的子序列个数。
考虑暴力
子序列要求本质不同。
假如每个位置向后每种字符的第一个位置连单向边。
设置一个虚点向区间每种字符第一个位置连单向边。
那么就是这个虚点出发有多少走法。
用另一种形式,你设f[i,j]表示最后走到了i,是从区间j第一次出现的位置开始走的,有多少走法。
你考虑i左移一格如何更新,发现
对于新的i,有f[i][a[i]]=1。
对于其他的i,有
假如当前做到l,[l,r]的答案是
我们继续用另一种形式表达如何计算[l,r]的答案。
有一个长度为9的ans数组,
它初始全0。接下来扫[l,r]的每一位,扫到i时做下列变化
最后的答案显然是
考虑优化
用一个1*10的矩阵存下ans,最后加一个常数1。
于是每次ans的变化可以用10*10的矩阵表示。
于是第i个位置有一个矩阵A[i]。
只要我们能求得[l,r]的A的积,就可以得到答案。
我们发现这个矩阵是可逆的,可以求出B[i]表示逆矩阵。
那么只要计算
即可。
于是可以预处理前缀和。
注意每次询问不要先算两个10*10矩阵的积,再与1*10矩阵相乘,直接用1*10矩阵乘过去即可。
#include<cstdio>#include<algorithm>#include<cstring>#define fo(i,a,b) for(i=a;i<=b;i++)#define fd(i,a,b) for(i=a;i>=b;i--)using namespace std;typedef long long ll;const int maxn=100000+10,mo=1000000007;int a[9][10][10],b[9][10][10],sum[maxn][10][10],num[maxn][10][10],o[10][10],c[10],d[10];char s[maxn];int i,j,k,l,r,t,n,m,ans;bool czy;int read(){ int x=0,f=1; char ch=getchar(); while (ch<'0'||ch>'9'){ if (ch=='-') f=-1; ch=getchar(); } while (ch>='0'&&ch<='9'){ x=x*10+ch-'0'; ch=getchar(); } return x*f;}int qsm(int x,int y){ if (!y) return 1; int t=qsm(x,y/2); t=(ll)t*t%mo; if (y%2) t=(ll)t*x%mo; return t;}void getb(int x){ int i,j,k,t; fo(i,0,9) b[x][i][i]=1; fo(i,0,9){ fo(j,i,9) if (a[x][j][i]){ fo(k,i,9){ swap(a[x][j][k],a[x][i][k]); swap(b[x][j][k],b[x][i][k]); } break; } fo(j,i+1,9){ t=(ll)a[x][j][i]*qsm(a[x][i][i],mo-2)%mo; fo(k,i,9){ (a[x][j][k]-=(ll)a[x][i][k]*t%mo)%=mo; (b[x][j][k]-=(ll)b[x][i][k]*t%mo)%=mo; } } } fd(i,9,0){ fo(j,i+1,9) if (a[x][i][j]){ fo(k,i,9){ (a[x][i][k]-=a[x][j][k])%=mo; (b[x][i][k]-=b[x][j][k])%=mo; } } }}int main(){ freopen("sub.in","r",stdin);freopen("sub.out","w",stdout); scanf("%s",s+1); n=strlen(s+1); fo(i,0,8){ fo(j,0,9) a[i][j][j]=1; fo(j,0,9) a[i][j][i]=1; getb(i); fo(j,0,9) fo(k,0,9) a[i][j][k]=0; fo(j,0,9) a[i][j][j]=1; fo(j,0,9) a[i][j][i]=1; } /*fo(i,0,9) fo(j,0,9) o[i][j]=0; fo(k,0,9) fo(i,0,9) fo(j,0,9) (o[i][j]+=(ll)a[1][i][k]*b[1][k][j]%mo)%=mo; czy=1; fo(i,0,9) fo(j,0,9) if (o[i][j]!=(i==j?1:0)){ czy=0; break; } printf("%d\n",czy);*/ fo(i,0,9) sum[0][i][i]=num[0][i][i]=1; fo(l,1,n){ t=s[l]-'a'; fo(i,0,9) fo(j,0,9) o[i][j]=0; fo(k,0,9) fo(i,0,9) fo(j,0,9) (o[i][j]+=(ll)sum[l-1][i][k]*a[t][k][j]%mo)%=mo; fo(i,0,9) fo(j,0,9) sum[l][i][j]=o[i][j]; fo(i,0,9) fo(j,0,9) o[i][j]=0; fo(k,0,9) fo(i,0,9) fo(j,0,9) (o[i][j]+=(ll)b[t][i][k]*num[l-1][k][j]%mo)%=mo; fo(i,0,9) fo(j,0,9) num[l][i][j]=o[i][j]; } m=read(); while (m--){ l=read();r=read(); fo(i,0,9) c[i]=d[i]=0; c[9]=1; fo(k,0,9) fo(j,0,9) (d[j]+=(ll)c[k]*num[l-1][k][j]%mo)%=mo; fo(i,0,9) c[i]=d[i],d[i]=0; fo(k,0,9) fo(j,0,9) (d[j]+=(ll)c[k]*sum[r][k][j]%mo)%=mo; ans=0; fo(i,0,8) (ans+=d[i])%=mo; (ans+=mo)%=mo; printf("%d\n",ans); }}
阅读全文
0 0
- [JZOJ5132][SDOI省队集训2017]子序列
- [bzoj4927][SDOI省队集训2017]diyiti
- [bzoj4928][SDOI省队集训2017]dierti
- [bzoj4930][SDOI省队集训2017]棋盘
- [bzoj4931][SDOI省队集训2017]塔
- [JZOJ5129][SDOI省队集训2017]字符串
- [JZOJ5133][SDOI省队集训2017]重建
- [JZOJ5136][SDOI省队集训2017]重排
- [JZOJ5131][SDOI省队集训2017]距离
- [JZOJ5130][51nod1446][SDOI省队集训2017]苹果树
- [JZOJ5134][SDOI省队集训2017]三元组
- [JZOJ5135][SDOI省队集训2017]逆序对
- [JZOJ5137][SDOI省队集训2017][bzoj4842]养猫
- 【SDOI省队集训题】棋盘(最小费用流)
- 【SDOI省队集训题】pair(线段树+二分)
- [莫队维护DP] LOJ#6074. 「2017 山东一轮集训 Day6」子序列
- 【BZOJ 4818】【SDOI 2017】序列计数
- [2017雅礼集训]day10 T2 数列 最长上升子序列
- Mysql操作
- 使用Docker在本地搭建Hadoop分布式集群
- http://www.cnblogs.com/davidwang456/articles/5258295.html
- Android 你好, 初次见面,以后要和谐一点
- Python机器学习应用--KNN
- [JZOJ5132][SDOI省队集训2017]子序列
- 在线云评测系统日志六
- 文件读写
- Web应用体系结构
- MVC与单元测试实践之健身网站(二)-管理员模块
- hibernate-HQL(query language)-16
- 排队接水(一)
- [JZOJ5133][SDOI省队集训2017]重建
- 选择客栈