2019湖南省賽 D Modulo Nine(DP)


題意:
n位數,給定m個區間使得任意區間數乘積爲9的倍數,求多少種構造方法。

思路:
要使得區間數的乘積爲9的倍數,至少得2個3/6,或者1個0/9。
定義f[i][j][k]f[i][j][k]代表到了第ii位時,最後兩個符合條件的數j,k,jkj,k,j≥k的位置。

對於每個區間,設置L[i]L[i]代表第ii個位置的最小區間的左下標。因爲相同右下標的區間,左下標更大肯定還是都成立,而且區間越小方案數相對越多。

那麼對於第ii個位置,
可以填 3/6,那麼

  1. ii個位置填1/2/4/5/7/8
    f[i][j][k]=(f[i][j][k]+f[i1][j][k]6);f[i][j][k] = (f[i][j][k] + f[i - 1][j][k] * 6);
  2. ii個位置填 3/6
    f[i][i][j]=(f[i][i][j]+f[i1][j][k]2);f[i][i][j] = (f[i][i][j] + f[i - 1][j][k] * 2) ;
  3. ii個位置填 0/9
    f[i][i][i]=(f[i][i][i]+f[i1][j][k]2);f[i][i][i] = (f[i][i][i] + f[i - 1][j][k] * 2);
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>

using namespace std;

typedef long long ll;

const int mod = 1e9 + 7;

ll L[55],f[55][55][55];

int main() {
    int n,m;
    while(~scanf("%d%d",&n,&m)) {
        memset(L,0,sizeof(L));
        memset(f,0,sizeof(f));
        
        for(int i = 1;i <= m;i++) {
            ll l,r;scanf("%lld%lld",&l,&r);
            L[r] = max(L[r],l);
        }
        
        f[0][0][0] = 1;
        for(int i = 1;i <= n;i++) {
            for(int j = L[i - 1];j <= i;j++) {
                for(int k = L[i - 1];k <= j;k++) {
                    f[i][j][k] = (f[i][j][k] + f[i - 1][j][k] * 6 % mod) % mod;
                    f[i][i][j] = (f[i][i][j] + f[i - 1][j][k] * 2 % mod) % mod;
                    f[i][i][i] = (f[i][i][i] + f[i - 1][j][k] * 2 % mod) % mod;
                }
            }
        }
        
        ll ans = 0;
        for(int i = L[n];i <= n;i++) {
            for(int j = L[n];j <= i;j++) {
                ans = (ans + f[n][i][j]) % mod;
            }
        }
        printf("%lld\n",ans);
    }
    return 0;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章