NOIP模拟72
T1:
注意读题!!!!
题目要求按一定排列进行合并,分析可以发现,每次b的贡献是一定的
即为大集合元素个数经若干次x * 2 + 1运算得到,并且对于集合i而言
最终合并出的a值必定属于max (a)/max (a + 1)
因此定义f[i][1/0]表示合并i集合所有元素最终的a值为max (a + 1) / max (a)
转移时大力分类讨论即可,需要注意的是,由于可能出现多种合并方式
因此需要记录所有合并方式的次数,在转移时需要乘以次数
代码如下:
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 a first 14 #define b second 15 #define lowbit(x) (x & -x) 16 #define debug cout << "It's Ok Here !" << endl; 17 #define FP(x) freopen (#x,"r",stdin) 18 #define FC(x) freopen (#x,"w",stdout) 19 const I mod = 1e9 + 7; 20 I n,k,a[18],b[20],MA[1 << 18],num[1 << 18],tmp[1 << 18]; 21 I f[1 << 18][2],p[1 << 18][2]; 22 inline I read () { 23 I x(0),y(1); C z(getchar()); 24 while (!isdigit(z)) { if (z == '-') y = -1; z = getchar(); } 25 while ( isdigit(z)) x = x * 10 + (z ^ 48), z = getchar(); 26 return x * y; 27 } 28 inline V Max (I &a,I b) { a = a > b ? a : b; } 29 inline V Min (I &a,I b) { a = a < b ? a : b; } 30 inline I max (I a,I b) { return a > b ? a : b; } 31 inline I min (I a,I b) { return a < b ? a : b; } 32 inline V swap (I &a,I &b) { a ^= b, b ^= a, a ^= b; } 33 inline I abs (I a) { return a >= 0 ? a : -a; } 34 inline P operator + (const P &a,const P &b) { 35 return MP (a.a + b.a,a.b + b.b); 36 } 37 inline P operator - (const P &a,const P &b) { 38 return MP (a.a - b.a,a.b - b.b); 39 } 40 inline V Mod1 (I &a,I b) { a = a + b > mod ? a + b - mod : a + b; } 41 inline I Mod2 (I a,I b) { return a + b > mod ? a + b - mod : a + b; } 42 signed main () { 43 FP (repair.in), FC (repair.out); 44 n = read (), k = read (); 45 for (I i(2);i <= n; ++ i) 46 b[i] = (b[i - 1] << 1) + 1; 47 for (I i(0);i < n; ++ i) 48 a[i] = read (), tmp[1 << i] = i; 49 for (I i(1);i < 1 << n; ++ i) { 50 num[i] = num[i - lowbit (i)] + 1; 51 MA[i] = max (MA[i - lowbit (i)],a[tmp[lowbit (i)]]); 52 if (lowbit (i) == i) { p[i][0] = 1; continue; } 53 for (I j(0);j < n; ++ j) if (1 << j & i) { 54 I t (1 << j ^ i); 55 if (a[j] == MA[t]) { 56 if (f[t][1] != 0) 57 Mod1 (f[i][1],Mod2((a[j] + 1) * k % mod * p[t][1] % mod,Mod2(f[t][1],b[num[t]] * p[t][1] % mod))), Mod1(p[i][1],p[t][1]); 58 Mod1 (f[i][1],Mod2((a[j] + 1) * k % mod * p[t][0] % mod,Mod2(f[t][0],b[num[t]] * p[t][0] % mod))), Mod1(p[i][1],p[t][0]); 59 } 60 if (a[j] > MA[t]) { 61 if (f[t][1] != 0) 62 a[j] == MA[t] + 1 ? (Mod1 (f[i][1],Mod2((a[j] + 1) * k % mod * p[t][1] % mod,Mod2(f[t][1],b[num[t]] * p[t][1] % mod))), Mod1(p[i][1],p[t][1])) : 63 (Mod1 (f[i][0],Mod2(a[j] * k % mod * p[t][1] % mod,Mod2(f[t][1],b[num[t]] * p[t][1] % mod))), Mod1(p[i][0],p[t][1])); 64 Mod1 (f[i][0],Mod2(a[j] * k % mod * p[t][0] % mod,Mod2(f[t][0],b[num[t]] * p[t][0] % mod))), Mod1(p[i][0],p[t][0]); 65 } 66 if (a[j] < MA[t]) { 67 if (f[t][1] != 0) 68 Mod1 (f[i][1],Mod2((MA[t] + 1) * k % mod * p[t][1] % mod,Mod2(f[t][1],b[num[t]] * p[t][1] % mod))), Mod1(p[i][1],p[t][1]); 69 Mod1 (f[i][0],Mod2(MA[t] * k % mod * p[t][0] % mod,Mod2(f[t][0],b[num[t]] * p[t][0] % mod))), Mod1(p[i][0],p[t][0]); 70 } 71 } 72 } 73 f[(1 << n) - 1][1] ? printf ("%lld %lld",MA[(1 << n) - 1] + 1,f[(1 << n) - 1][1]) : printf ("%lld %lld",MA[(1 << n) - 1],f[(1 << n) - 1][0]); 74 }
注意挂点在于DP方程的设计,由于贡献以及次数的考虑,考场直接取元素标号为下标
利用结构体存储元素进行转移,转移方程难以处理,而发现题目中要求的是a值最大
因此以a值为下标转移过程中记录b以及次数即可,DP方程设计时一定要注意题目要求
T3:
比较明显的AC自动机,多字符串匹配,可以想到的是构建fail树,在fail树上不断跳指针
直到到达所需字符串,然而这种方式需要大量记录字符串标号,空间难以承受
考虑如何在fail树上快速查询合适的字符串,接下来是高老师的做法,考虑由于询问间是
相互独立的,那么考虑对于每一个T串,我们将询问独立,分别处理T串所能做出的最大贡献
也就是,枚举T串,遍历其所有节点,在fail树上对于子树做区间最值修改,再枚举所有与T有关的
查询,若线段树上S串的位置被打上标记,则记录答案,否则答案为0,这里需要注意的是
在不同询问之间需要通过时间戳判断线段树上的标记是否是当前询问的标记,这样处理不同询问
具体实现,线段树可以采用pair进行时间戳+最值的同时维护
代码如下:
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 a first 14 #define b second 15 #define lowbit(x) (x & -x) 16 #define debug cout << "It's Ok Here !" << endl; 17 #define FP(x) freopen (#x,"r",stdin) 18 #define FC(x) freopen (#x,"w",stdout) 19 const I N = 6e5 + 3, Q = 1e6 + 3; 20 C s[N]; 21 I n,q,ans[Q]; 22 vector <I> poi[N]; 23 vector <P> que[N]; 24 I tot,head[N],to[N],nxt[N]; 25 I cnt,dfn[N],size[N],d[N]; 26 inline I read () { 27 I x(0),y(1); C z(getchar()); 28 while (!isdigit(z)) { if (z == '-') y = -1; z = getchar(); } 29 while ( isdigit(z)) x = x * 10 + (z ^ 48), z = getchar(); 30 return x * y; 31 } 32 inline V Max (I &a,I b) { a = a > b ? a : b; } 33 inline V Min (I &a,I b) { a = a < b ? a : b; } 34 inline I max (I a,I b) { return a > b ? a : b; } 35 inline I min (I a,I b) { return a < b ? a : b; } 36 inline V swap (I &a,I &b) { a ^= b, b ^= a, a ^= b; } 37 inline I abs (I a) { return a >= 0 ? a : -a; } 38 inline P operator + (const P &a,const P &b) { 39 return MP (a.a + b.a,a.b + b.b); 40 } 41 inline P operator - (const P &a,const P &b) { 42 return MP (a.a - b.a,a.b - b.b); 43 } 44 inline V found (I x,I y) { 45 to[++tot] = y, nxt[tot] = head[x], head[x] = tot; 46 } 47 struct AC { 48 #define c (s[i] - 'a') 49 I tot,it[N][26],fail[N]; 50 inline V insert (I idx) { 51 I pos (0); 52 for (I i(0); s[i] ; ++ i) { 53 if (!it[pos][c]) 54 it[pos][c] = ++tot, d[tot] = d[pos] + 1; 55 pos = it[pos][c], poi[idx].push_back (pos); 56 } 57 } 58 inline V getmap () { 59 queue <I> q; 60 for (I i(0);i < 26; ++ i) if (it[0][i]) 61 q.push (it[0][i]); 62 while (!q.empty ()) { 63 I x (q.front ()); q.pop (); 64 for (I i(0);i < 26; ++ i) 65 if (it[x][i]) 66 fail[it[x][i]] = it[fail[x]][i], q.push (it[x][i]); 67 else 68 it[x][i] = it[fail[x]][i]; 69 } 70 for (I i(1);i <= tot; ++ i) found (fail[i],i); 71 } 72 }AC; 73 V Dfs (I x) { 74 dfn[x] = ++cnt, size[x] = 1; 75 for (I i(head[x]),y(to[i]); i ;i = nxt[i],y = to[i]) 76 Dfs (y), size[x] += size[y]; 77 } 78 struct SGT { 79 #define lid id << 1 80 #define rid id << 1 | 1 81 #define mid (l + r >> 1) 82 #define update(id) (MA[id] = max (MA[lid],MA[rid])) 83 P MA[N << 2],lazy[N << 2]; 84 inline V pushdown (I id) { 85 MA[lid] = max (MA[lid],lazy[id]); 86 MA[rid] = max (MA[rid],lazy[id]); 87 lazy[lid] = max (lazy[lid],lazy[id]); 88 lazy[rid] = max (lazy[rid],lazy[id]); 89 lazy[id] = MP (0,0); 90 } 91 V secmod (I id,I l,I r,I ql,I qr,P x) { 92 if (ql <= l && r <= qr) 93 return (V)(MA[id] = max (MA[id],x), lazy[id] = max (lazy[id],x)); 94 if (lazy[id] != MP (0,0) && l != r) pushdown (id); 95 if (ql <= mid) secmod (lid,l,mid,ql,qr,x); 96 if (qr > mid) secmod (rid,mid + 1,r,ql,qr,x); 97 update (id); 98 } 99 P poique (I id,I l,I r,I pos) { 100 if (l == r) return MA[id]; 101 if (lazy[id] != MP (0,0)) pushdown (id); 102 return pos <= mid ? poique (lid,l,mid,pos) : poique (rid,mid + 1,r,pos); 103 } 104 }SGT; 105 signed main () { 106 FP (string.in), FC (string.out); 107 n = read (), q = read (); 108 for (I i(1);i <= n; ++ i) 109 scanf ("%s",s), AC.insert (i); 110 AC.getmap (), Dfs (0); 111 for (I i(1);i <= q; ++ i) { 112 I x (read ()), y (read ()); 113 que[y].push_back (MP (x,i)); 114 } 115 for (I i(1);i <= n; ++ i) if (!que[i].empty ()) { 116 for (auto x : poi[i]) 117 SGT.secmod (1,1,cnt,dfn[x],dfn[x] + size[x] - 1,MP (i,d[x])); 118 for (auto x : que[i]) { 119 P tmp (SGT.poique (1,1,cnt,dfn[poi[x.a][poi[x.a].size () - 1]])); 120 ans[x.b] = tmp.a == i ? tmp.b : 0; 121 } 122 } 123 for (I i(1);i <= q; ++ i) printf ("%d\n",ans[i]); 124 }