NOIP模拟58

T2:

  首先对于非常规模数要思考其是否为质数,因为逆元与费马小定理建立在质数(互质)情况下

那么对于模数非质数的问题,通常的解决方法为唯一分解,即将模数分解为若干质数之积,再通过

中国剩余定理合并

  对于本题,发现模数为5个连续质数之积,又给出了公式二,因此基本思路非常简单,利用基本公式二

作矩阵乘法优化递推,对每个模数计算出x,最终将x模原质数即可

代码如下:

NOIP模拟58
  1 #include <bits/stdc++.h>
  2 using namespace std;
  3 #define I long long
  4 #define C char
  5 #define B bool
  6 #define V void
  7 #define D double
  8 #define LL long long
  9 #define UI unsigned int
 10 #define UL unsigned long long
 11 #define P pair<I,I>
 12 #define MP make_pair
 13 #define fir first
 14 #define sec second
 15 #define lowbit(x) (x & -x)
 16 const I N = 56569200, mod = 95041567;
 17 I T,gcd,A[47],F[47][47],G[6];
 18 I prime[6] = {0,31,37,41,43,47};
 19 I Bel[47];
 20 vector <I> _C[48];
 21 inline I read () {
 22     I x(0),y(1); C z(getchar());
 23     while (!isdigit(z)) { if (z == '-') y = -1; z = getchar(); }
 24     while ( isdigit(z))  x = x * 10 + (z ^ 48), z = getchar();
 25     return  x * y;
 26 }
 27 inline V Max (I &a,I b) { a = a > b ? a : b; }
 28 inline V Min (I &a,I b) { a = a < b ? a : b; }
 29 inline I max (I a,I b) { return a > b ? a : b; }
 30 inline I min (I a,I b) { return a < b ? a : b; }
 31 inline V swap (I &a,I &b) { a ^= b, b ^= a, a ^= b; }
 32 inline I fp (I a,I b) { I ans(1);
 33     for (; b ;b >>= 1, a = 1ll * a * a % mod)
 34         if (b & 1) ans = 1ll * ans * a % mod;
 35     return ans;
 36 }
 37 I Exgcd (I a,I b,I &x,I &y) {
 38     if (b == 0) {
 39         x = 1, y = 0;
 40         return a;
 41     }
 42     gcd = Exgcd (b,a % b,x,y);
 43     I tmp (x);
 44     x = y;
 45     y = tmp - a / b * y;
 46     return gcd;
 47 }
 48 I China () {
 49     I x,y,a(0),m;
 50     for (I i(1);i <= 5; ++ i) {
 51         m = mod / prime[i];
 52         Exgcd (prime[i],m,x,y);
 53         a = (a + 1ll * y * m * G[i] % mod) % mod;
 54     }
 55     if (a > 0) return a;
 56     else       return a + mod;
 57 }
 58 inline V Make (I size) {
 59     for (I i(0);i < size; ++ i)
 60         A[i] = Bel[i + 1] % size;
 61     for (I j(0);j < size; ++ j) 
 62         for (I i(0);i < size; ++ i) 
 63             F[i][j] = j == i - 1;
 64     F[0][size - 1] = F[1][size - 1] = 1;
 65 }
 66 inline V Matrix_mul (I size) {
 67     I X[47];
 68     memset (X,0,sizeof X);
 69     for (I k(0);k < size; ++ k)
 70         for (I j(0);j < size; ++ j)
 71             (X[j] += 1ll * A[k] * F[k][j] % mod) %= mod;
 72     memcpy (A,X,sizeof X);
 73 }
 74 inline V Matrix_self (I size) {
 75     I X[47][47];
 76     memset (X,0,sizeof X);
 77     for (I i(0);i < size; ++ i)
 78         for (I k(0);k < size; ++ k)
 79             for (I j(0);j < size; ++ j)
 80                 (X[i][j] += 1ll * F[i][k] * F[k][j] % mod) %= mod; 
 81     memcpy (F,X,sizeof X);
 82 }
 83 inline V FMP (I t,I size) {
 84     for (; t ;t >>= 1, Matrix_self (size))
 85         if (t & 1) Matrix_mul (size);
 86 }
 87 inline V Figure (I t) {
 88     for (I i(1);i <= 5; ++ i) {
 89         Make (prime[i]);
 90         if (t > prime[i]) {
 91             FMP (t - prime[i],prime[i]);
 92             G[i] = A[prime[i] - 1];
 93         }
 94         else 
 95             G[i] = A[t - 1];
 96     }
 97     printf ("%lld\n",China () % mod);
 98 }
 99 signed main () {
100     T = read();
101     _C[0].push_back (1), _C[0].push_back (0);
102     for (I i(1);i < 48; ++ i) {
103         _C[i].push_back (1);
104         for (I j(1);j <= i; ++ j)
105             _C[i].push_back ((_C[i - 1][j - 1] + _C[i - 1][j]) % mod);
106         _C[i].push_back (0);
107     }
108     Bel[0] = 1;
109     for (I i(1);i < 48; ++ i) 
110         for (I j(0);j <  i; ++ j)
111             (Bel[i] += 1ll * _C[i - 1][j] * Bel[j] % mod) %= mod;
112     while (T -- ) 
113         Figure (read());
114 }
View Code

矩阵乘法可应用与加速线性递推,中国剩余定理应用于当模数难以计算时分解为若*分再将结果合并

T3:

  正解AC自动机+DP,考虑首先模型是对的,多字符串匹配,只不过有限制转移,考场考虑成计数问题

于是就挂了,考虑设Fijkl表示当前字符串长度为i,有j个R,已经转移到AC自动机上k节点,l为0,1,2,3

表示是否包含两个字符串,最终目标为F(n+m)(m)()(3)

  AC自动机+DP关键在于AC自动机的失配指针,利用其直接转移到下一个合法位置,另一在于AC自动机建立过程中

失配指针的建立过程,需要注意利用fail指针的传递将信息进行传递,即若某些问题中子串与母串具有相同性质,需要

传递信息

代码如下:

NOIP模拟58
 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define I int
 4 #define C char
 5 #define B bool
 6 #define V void
 7 #define D double
 8 #define LL long long
 9 #define UI unsigned int
10 #define UL unsigned long long
11 #define P pair<I,I>
12 #define MP make_pair
13 #define fir first
14 #define sec second
15 #define lowbit(x) (x & -x)
16 const I M = 105, mod = 1e9 + 7;
17 I f[M << 1][M][M << 1][4];
18 C s[M];
19 inline I read () {
20     I x(0),y(1); C z(getchar());
21     while (!isdigit(z)) { if (z == '-') y = -1; z = getchar(); }
22     while ( isdigit(z))  x = x * 10 + (z ^ 48), z = getchar();
23     return  x * y;
24 }
25 inline V Max (I &a,I b) { a = a > b ? a : b; }
26 inline V Min (I &a,I b) { a = a < b ? a : b; }
27 inline I max (I a,I b) { return a > b ? a : b; }
28 inline I min (I a,I b) { return a < b ? a : b; }
29 inline V swap (I &a,I &b) { a ^= b, b ^= a, a ^= b; }
30 struct AC {
31     #define c (s[i] == 'R')
32     I tot,it[M << 1][2],fail[M << 1],End[M << 1];
33     inline V insert (I idx) {
34         I pos(0);
35         for (I i(0); s[i] ; ++ i) {
36             if (!it[pos][c])
37                 it[pos][c] = ++tot;
38             pos = it[pos][c];
39         }
40         End[pos] |= idx;
41     }
42     inline V found () {
43         queue <I> q;
44         if (it[0][0]) q.push (it[0][0]);
45         if (it[0][1]) q.push (it[0][1]);
46         while (!q.empty ()) {
47             I x (q.front ()); q.pop ();
48             if (it[x][1]) fail[it[x][1]] = it[fail[x]][1], q.push (it[x][1]);
49             else it[x][1] = it[fail[x]][1];
50             if (it[x][0]) fail[it[x][0]] = it[fail[x]][0], q.push (it[x][0]);
51             else it[x][0] = it[fail[x]][0];
52             End[it[x][1]] |= End[it[fail[x]][1]];
53             End[it[x][0]] |= End[it[fail[x]][0]];
54         }
55     }
56     inline V clear () {
57         for (I i(0);i <= tot; ++ i) 
58             it[i][0] = it[i][1] = fail[i] = End[i] = 0;
59         tot = 0;
60     }
61 }AC;
62 signed main () {
63     I T(read());
64     while (T -- ) {
65         AC.clear (); 
66         I ans(0), m(read()), n(read());
67         scanf ("%s",s); AC.insert (1);
68         scanf ("%s",s); AC.insert (2);
69         AC.found ();
70         f[0][0][0][0] = 1;
71         for (I i(0);i <= n + m; ++ i) 
72             for (I j(0);j <= i; ++ j) {
73                 if (j > m || i - j > n) continue;
74                 for (I k(0);k <= AC.tot; ++ k) {
75                     for (I l(0);l <= 3; ++ l) {
76                         (f[i + 1][j + 1][AC.it[k][1]][l | AC.End[AC.it[k][1]]] += f[i][j][k][l]) %= mod;
77                         (f[i + 1][  j  ][AC.it[k][0]][l | AC.End[AC.it[k][0]]] += f[i][j][k][l]) %= mod;
78                     }
79                 }
80             }
81         for (I i(0);i <= AC.tot; ++ i)
82             (ans += f[n + m][m][i][3]) %= mod;
83         printf ("%d\n",ans);
84         for (I i(0);i <= n + m + 1; ++ i)
85             for (I j(0);j <= i + 1; ++ j) 
86                 for (I k(0);k <= AC.tot; ++ k)
87                     f[i][j][k][0] = f[i][j][k][1] = f[i][j][k][2] = f[i][j][k][3] = 0;
88     }
89 }
View Code

 

上一篇:Noip模拟62 2021.9.26


下一篇:NOIP模拟56