Luogu3702 SDOI2017 序列计数 矩阵DP

时间:2023-03-09 05:00:41
Luogu3702 SDOI2017 序列计数 矩阵DP

传送门


不考虑质数的条件,可以考虑到一个很明显的$DP:$设$f_{i,j}$表示选$i$个数,和$mod\ p=j$的方案数,显然是可以矩阵优化$DP$的。

而且转移矩阵是循环矩阵,所以可以只用第一行的数字代替整个矩阵。当然了这道题$p \leq 100$矩阵比较小也可以直接做。

然后考虑至少要一个质数的条件,发现就是所有数参与$DP$的答案减去所有合数参与$DP$的答案,两次算出来相减即可。

 #include<bits/stdc++.h>
 #define ll long long
 //This code is written by Itst
 using namespace std;

 inline int read(){
     ;
     char c = getchar();
     ;
     while(!isdigit(c)){
         if(c == '-')
             f = ;
         c = getchar();
     }
     while(isdigit(c)){
         a = (a << ) + (a << ) + (c ^ ');
         c = getchar();
     }
     return f ? -a : a;
 }

 ;
 int N , M , P , ans;
 ];
 struct matrix{
     ll a[];
     matrix(){memset(a ,  , sizeof(a));}
     inline ll& operator [](int x){return a[x];}
     matrix operator *(matrix b){
         matrix c;
          ; i < P ; ++i)
              ; j < P ; ++j)
                 c[i] += a[j] * b[i - j <  ? i - j + P : i - j];
          ; j < P ; ++j)
             c[j] %= MOD;
         return c;
     }
 }S , T , G;

 int main(){
 #ifndef ONLINE_JUDGE
     freopen("in" , "r" , stdin);
     //freopen("out" , "w" , stdout);
 #endif
     N = read();
     M = read();
     P = read();
      ; i < P && i <= M ; ++i)
         G[i % P] = (M - i) / P + (bool)i;
     S[] = ;
     T = G;
     int K = N;
     while(K){
         )
             S = S * T;
         T = T * T;
         K >>= ;
     }
     ans = S[];
      ; i <= M ; ++i)
         if(!nprime[i]){
             --G[i % P];
             for(int j = i ; j <= M / i ; ++j)
                 nprime[i * j] = ;
         }
     T = G;
     S = matrix();
     S[] = ;
     K = N;
     while(K){
         )
             S = S * T;
         T = T * T;
         K >>= ;
     }
     cout << (ans - S[] + MOD) % MOD;
     ;
 }