给出一个
n
≤
50
n\leq50
n≤50的允许有前导0的数字串,以及
m
≤
50
m\leq50
m≤50个区间
[
l
,
r
]
[l,r]
[l,r]求满足所有的区间的数字乘积是9的倍数的方案数。
满足乘积是9的倍数即这个区间有超过2个9的质因子也就是3的个数要超过2个。显然3,6各有一个,9有两个,而0只要出现就一定是9的倍数,这里也可以认为是两个。记录下两个最近的因子的位置
f
i
,
j
,
k
f_{i,j,k}
fi,j,k表示到
i
i
i位,两个最近的质因子分别在
j
,
k
j,k
j,k位置的方案数。枚举下一位的数字暴力转移。
需要记录下当前位置作为右端点的最大左边界,判定当前的状态是否合法。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
static const int maxn = 100010;
static const int INF = 0x3f3f3f3f;
static const int mod = (int)1e9 + 7;
static const double eps = 1e-6;
static const double pi = acos(-1);
void redirect(){
#ifdef LOCAL
freopen("test.txt","r",stdin);
#endif
}
const int N=55;
int lim[N];
ll f[N][N][N];
void add(ll &x,ll y) { x+=y; if(x>=mod) x-=mod; }
int main(){
// redirect();
int n,m;
while(scanf("%d%d",&n,&m)!=EOF) {
memset(lim,0,sizeof(lim));
memset(f,0,sizeof(f));
for(int l,r,i=1;i<=m;i++) {
scanf("%d%d",&l,&r);
lim[r]=max(lim[r],l);
}
f[0][0][0]=1;
for(int i=0;i<n;i++) {
for(int j=0;j<=i;j++) {
for(int k=0;k<=j;k++) {
if(k>=lim[i]) {
add(f[i+1][i+1][i+1],2*f[i][j][k]%mod);
add(f[i+1][i+1][j],2*f[i][j][k]%mod);
add(f[i+1][j][k],6*f[i][j][k]%mod);
}
}
}
}
ll ans=0;
for(int j=0;j<=n;j++) {
for(int k=0;k<=j;k++) {
if(k>=lim[n]) add(ans,f[n][j][k]);
}
}
printf("%lld\n",ans);
}
return 0;
}