"Bus lines like matrix multiplication accelerated pressure dp"

<> Yes

<First update>


<Text>

bus routes

Description

Z small cities where there are N bus stops, are arranged on a straight line km length (N-1), from left to right are numbered 1 to N, the distance between the adjacent bus stop are 1km. As planners bus lines, the small Z investigate the needs of the public, according to the following decision rule design lines:

1. buses K were provided, the number 1 to the originating station as a station K, N-K + 1 to the number N as a terminal station.

2. Each station must be one and only one bus pass (departure station and terminal are also considered to be through).

3. Bus station only from a small number heading higher numbered stations.

4. a bus through two adjacent

The distance between the platform shall not exceed Pkm. Before the final design line, the small Z wanted to know how many meet the requirements of the program. Since the answer may be large, you just

Demand results for 30031 modulo answer.

Input Format

Only one line contains three positive integers NKP, each represent a bus stop, bus number, distance limitations of the adjacent platform.

N<=10^9,1<P<=10,K<N,1<K<=P

Output Format

Only contains an integer representing the number of programs to meet the requirements of the result modulo 30031.

Sample Input

10 2 4

Sample Output

81

Resolve

问题转换:求个\(n\)个变量\(x_{1-n}\)\([1,k]\)之间的值的方案数,需要满足:\(x_{1-k}\)取遍\(1-k\)\(x_{(n-k+1)-n}\)取遍\(1-k\),任意一个区间\([t,t+p-1]\)\(1-k\)的数至少出现一次。

距离的限制其实就是上述问题转换中的最后一条限制。

考虑状压\(dp\),由于\(p\)很小,我们就压一下当前阶段那个长度为\(p\)的区间的赋值情况。也就是说,\(f[i][S]\)代表前\(i-1\)个变量一个完成赋值,区间\([i,i+p-1]\)\(1-k\)这些数的赋值情况为\(S\)的方案数。\(S\)是一个长度为\(p\)的二进制数,共有\(k\)\(1\),从最高位开始数,\(S\)的第\(j\)位为\(1\),代表\(x_{i+j-1}\)被赋值为了一个\(1-k\)之间的数(我们不关心每一个数的具体位置,只需要保证这\(k\)个数在这个区间内每个出现至少一次即可),作为当前区间合法性的关键值,其他变量随意。对于任意的\(S\),需满足最高位为\(1\),是因为我们必须保证第\(i\)位取,这样才能保证最后所有变量都赋了值。

转移当然是由上一个阶段转移而来,方程就是:
\[f[i][S]=\sum_{valid(S',S)} f[i-1][S']\]

如何判定两个状态直接可以转移?首先两个状态的区间只差了一个位置。也就是\(S'\)的最高位在\(S\)中不存在,那么我们就把最高位取走,然后在最低位后面补\(0\),如果此时\(S'\)\(S\)的子集,那么我们只需在第\(i+p-1\)这个位置补上刚才取走的那个数就又是合法的方案了。所以,当操作完后的状态\(S'\)\(S\)的子集时,可以转移。

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+20 , SIZE = 130 , Mod = 30031;
int n,K,P,f[N][SIZE],S[SIZE],tot,ans;
inline void input(void)
{
    scanf("%d%d%d",&n,&K,&P);
}
inline int add(int a,int b) { return a + b >= Mod ? a + b - Mod : a + b; }
inline void Add(int &a,int b) { a = add( a , b ); }
inline void DynamicProgram(void)
{
    for (int i=1<<P-1;i<1<<P;i++)
    {
        int cnt = 0;
        for (int j=1;j<=P;j++)
            cnt += ( i >> (j-1) & 1 );
        if ( cnt == K ) S[++tot] = i;
    }
    f[1][tot] = 1;
    for (int i=2;i<=n-K+1;i++)
        for (int j=1;j<=tot;j++)
            for (int k=1;k<=tot;k++)
            {
                int S1 = S[k] , S2 = S[j];
                int S3 = S1 - (1<<P-1) << 1;
                for (int l=1;l<=P;l++)
                    if ( not( S3 >> (l-1) & 1 ) && ( S3 + (1<<l-1) == S2 ) )
                        Add( f[i][j] , f[i-1][k] );
            }
}
int main(void)
{
    input();
    DynamicProgram();
    printf("%d\n",f[n-K+1][tot]);
    return 0;
}

这样的动态规划算法的时间复杂度为\(O(nC_{p-1}^{k-1})\),使用矩阵乘法加速,时间复杂度为\(O((C_{p-1}^{k-1})^3\log_2n)\)

\(Code:\)

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+20 , SIZE = 130 , Mod = 30031;
int n,K,P,S[SIZE],f[SIZE],tot;
inline int add(int a,int b) { return a + b >= Mod ? a + b - Mod : a + b; }
inline int mul(int a,int b) { return 1LL * a * b % Mod; }
inline void Add(int &a,int b) { a = add( a , b ); }
struct Matrix
{
    int mat[SIZE][SIZE];
    Matrix () { memset( mat , 0 , sizeof mat ); }
    friend Matrix operator * (Matrix a,Matrix b)
    {
        Matrix c;
        for (int i=1;i<=tot;i++)
            for (int j=1;j<=tot;j++)
                for (int k=1;k<=tot;k++)
                    Add( c.mat[i][j] , mul( a.mat[i][k] , b.mat[k][j] ) );
        return c;
    }
};
Matrix Trans;
inline void Maxtrixmul(int *a,Matrix b)
{
    int c[SIZE] = {};
    for (int j=1;j<=tot;j++)
        for (int k=1;k<=tot;k++)
            Add( c[j] , mul( a[k] , b.mat[k][j] ) );
    memcpy( a , c , sizeof c );
}
inline void DynamicProgram(void)
{
    for (int i=1<<P-1;i<1<<P;i++)
    {
        int cnt = 0;
        for (int j=1;j<=P;j++)
            cnt += ( i >> (j-1) & 1 );
        if ( cnt == K ) S[++tot] = i;
    }
    for (int i=1;i<=tot;i++)
        for (int j=1;j<=tot;j++)
        {
            int S1 = S[i] , S2 = S[j];
            int S3 = S1 - (1<<P-1) << 1;
            for (int k=1;k<=P;k++)
                if ( not( S3 >> (k-1) & 1 ) && ( S3 + (1<<k-1) == S2 ) )
                    Trans.mat[i][j] = 1;
        }
    int T = n - K; f[tot] = 1;
    while ( T )
    {
        if ( 1 & T ) Maxtrixmul( f , Trans );
        Trans = Trans * Trans , T >>= 1;
    }
}
int main(void)
{
    scanf("%d%d%d",&n,&K,&P);
    DynamicProgram();
    printf("%d\n",f[tot]);
    return 0;
}

<后记>

Guess you like

Origin www.cnblogs.com/Parsnip/p/11520457.html