不考虑质数的条件,可以考虑到一个很明显的$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; ; }