传送门
题意:有一个长度为n的由0~9组成的数字串,其中已知有m个区间的区间乘积%9==0,求满足条件的数字串的个数%(1e9+7)的结果
题解:要想区间乘积是9的倍数,区间内因子3的个数至少为2个,其中0和9相当于2个3,3和6相当于1个3,其余数字相当于0个3,那么可以用dp[i][j][k]表示前i个里面距离i最近的两个3在j和k位置的情况数,如果两个区间的右端点一样,那么显然只要使最小的那个区间满足条件即可,转移过程对于第i个位置,只有k>=L[i-1]时才使用dp[i-1][j][k]更新和i有关的dp值,这样可以保证是使用前i-1个合法情况进行转移的,这时也不需要考虑第i个是否满足>=L[i],因为反正后面i+1使用的也是k>=L[i]的情况。这种通过限定转移过程的dp是很常见的
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int maxn=1e5+5;
#define debug(x) cout<<#x<<" is "<<x<<endl;
ll dp[55][55][55];
int l[55];
int main(){
int n,m;
while(scanf("%d%d",&n,&m)==2){
memset(dp,0,sizeof(dp));
memset(l,0,sizeof(l));
for(int i=1;i<=m;i++){
int a,b;
scanf("%d%d",&a,&b);
l[b]=max(l[b],a);
}
dp[0][0][0]=1;
for(int i=1;i<=n;i++){
for(int j=0;j<i;j++){
for(int k=0;k<=j;k++){
if(k>=l[i-1]){
dp[i][j][k]=(dp[i][j][k]+6*dp[i-1][j][k])%mod;
dp[i][i][j]=(dp[i][i][j]+2*dp[i-1][j][k])%mod;
dp[i][i][i]=(dp[i][i][i]+2*dp[i-1][j][k])%mod;
}
}
}
}
ll ans=0;
for(int i=0;i<=n;i++){
for(int j=0;j<=i;j++){
if(j>=l[n]){
ans=(ans+dp[n][i][j])%mod;
}
}
}
printf("%lld\n",ans);
}
return 0;
}