Luogu3702 SDOI2017 序列计数 矩阵DP

Posted itst

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu3702 SDOI2017 序列计数 矩阵DP相关的知识,希望对你有一定的参考价值。

传送门


 

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

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

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

 1 #include<bits/stdc++.h>
 2 #define ll long long
 3 //This code is written by Itst
 4 using namespace std;
 5 
 6 inline int read(){
 7     int a = 0;
 8     char c = getchar();
 9     bool f = 0;
10     while(!isdigit(c)){
11         if(c == -)
12             f = 1;
13         c = getchar();
14     }
15     while(isdigit(c)){
16         a = (a << 3) + (a << 1) + (c ^ 0);
17         c = getchar();
18     }
19     return f ? -a : a;
20 }
21 
22 const int MOD = 20170408;
23 int N , M , P , ans;
24 bool nprime[(int)2e7 + 10];
25 struct matrix{
26     ll a[110];
27     matrix(){memset(a , 0 , sizeof(a));}
28     inline ll& operator [](int x){return a[x];}
29     matrix operator *(matrix b){
30         matrix c;
31         for(int i = 0 ; i < P ; ++i)
32             for(int j = 0 ; j < P ; ++j)
33                 c[i] += a[j] * b[i - j < 0 ? i - j + P : i - j];
34         for(int j = 0 ; j < P ; ++j)
35             c[j] %= MOD;
36         return c;
37     }
38 }S , T , G;
39 
40 int main(){
41 #ifndef ONLINE_JUDGE
42     freopen("in" , "r" , stdin);
43     //freopen("out" , "w" , stdout);
44 #endif
45     N = read();
46     M = read();
47     P = read();
48     for(int i = 0 ; i < P && i <= M ; ++i)
49         G[i % P] = (M - i) / P + (bool)i;
50     S[0] = 1;
51     T = G;
52     int K = N;
53     while(K){
54         if(K & 1)
55             S = S * T;
56         T = T * T;
57         K >>= 1;
58     }
59     ans = S[0];
60     for(int i = 2 ; i <= M ; ++i)
61         if(!nprime[i]){
62             --G[i % P];
63             for(int j = i ; j <= M / i ; ++j)
64                 nprime[i * j] = 1;
65         }
66     T = G;
67     S = matrix();
68     S[0] = 1;
69     K = N;
70     while(K){
71         if(K & 1)
72             S = S * T;
73         T = T * T;
74         K >>= 1;
75     }
76     cout << (ans - S[0] + MOD) % MOD;
77     return 0;
78 }

以上是关于Luogu3702 SDOI2017 序列计数 矩阵DP的主要内容,如果未能解决你的问题,请参考以下文章

P3702 [SDOI2017]序列计数

做题记录

Luogu P4071[SDOI2016]排列计数

LibreOJ #2002. 「SDOI2017」序列计数

[Sdoi2017]序列计数

BZOJ4818: [Sdoi2017]序列计数