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 }
View Code

注意挂点在于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 }
View Code

 

posted @ 2021-10-10 16:06  HZOI_LYM  阅读(47)  评论(0编辑  收藏  举报