P9490题解
Raymondzll · · 题解
P9490 ZHY 的矩阵
前言
一道 DP 好题。
很多人(包括出题人)都反映此题题面过于抽象。我自己在做题时把题面翻译了一下。此部分不是太重要,能读懂即可。
考虑将二维的
则题目限制转化为:若
题目条件转化为:规定
下面进入正题。
解题思路
由出题人题解我们基本可以看到有
令
先不考虑断点等于某数或不等于某数的限制,从上一个断点逐位递推的过程是怎样的呢?
记
好。先解释一下怎么推出来的。如果这一列的数(
如果上一位末位是
我们发现了什么?这一位末位是
有了这些基础我们就以逐断点递推很近了,但我们先要解决一下式子的问题。参照上面的表格,表格第二列的值为
通式为
准备工作均已完成,设
等于:
设规定了
因此
对于
不等于:
设规定了
到这里重点的转移已经结束了。如果
const ll P=1000000007;
ll n,k,x,X;
ll f[200010][110],sum[200010];
int a[200010],b[200010],c[200010];
int l[200010],flag[200010];
void init(){
cin>>n>>k>>x;
for(int i=1;i<=x;i++){
cin>>a[i]>>b[i]>>c[i];
l[i]=b[i];
}
sort(l+1,l+x+1);
X=unique(l+1,l+x+1)-l-1;//离散化
for(int i=1;i<=x;i++){
b[i]=lower_bound(l+1,l+X+1,b[i])-l;
if(c[i]==1){
if(++flag[b[i]]>1){cout<<0;exit(0);}
for(int j=0;j<=k;j++)if(j!=a[i])f[b[i]][j]=-1;
}else f[b[i]][a[i]]=-1;
}
}
ll ksm(ll a,ll b){
ll res=1;
while(b){if(b&1)(res*=a)%=P;(a*=a)%=P;b>>=1;}
return res;
}
ll invk;
int main(){
init();invk=ksm(k-1,P-2);
f[0][0]=1;
if(l[X]!=n)l[++X]=n;
for(int i=1;i<=X;i++){
int d=l[i]-l[i-1];
if(flag[i]){
f[i][0]=0;
for(int j=1;j<=k;j++)
if(f[i][j]==0){
if(d==1)f[i][j]=sum[i]=(f[i-1][0]+sum[i-1]-f[i-1][j])%P;
else f[i][j]=sum[i]=(ksm(k,d-1)*f[i-1][0]%P+(k-1)*ksm(k,d-2)%P*sum[i-1]%P)%P;
}else{
f[i][j]=0;
}
}else{
f[i][0]=f[i-1][0];
for(int j=1;j<=k;j++)
if(f[i][j]==0){
if(d==1)f[i][j]=(f[i-1][0]+sum[i-1])%P;
else f[i][j]=((ksm(k,d)-1)*invk%P*f[i-1][0]%P+ksm(k,d-1)*sum[i-1]%P)%P;
(sum[i]+=f[i][j])%=P;
}else{
if(d==1)f[i][j]=f[i-1][j];
else f[i][j]=((ksm(k,d-1)-1)*invk%P*f[i-1][0]%P+ksm(k,d-2)*sum[i-1]%P)%P;
(sum[i]+=f[i][j])%=P;
}
}
}
cout<<(sum[X]+f[X][0]+P)%P;
return 0;
}