Noi2011部分题解

道路修建

简直是送分题。。。

先算出$f_x$表示以$x$为根的子树大小,然后每条边$(x,y)$的贡献显然就是$|n - f_y - f_y|$

$dfs$一遍即可。

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 inline char Getchar()
 5 {
 6     static char buf[1000010], *p1 = buf, *p2 = buf;
 7     return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 1000000, stdin), p1 == p2) ? EOF : *p1++;
 8 }
 9 
10 inline int Read()
11 {
12     int x = 0, f = 1; char s = Getchar();
13     for(; !isdigit(s); s = Getchar()) if(s == '-') f = -1;
14     for(; isdigit(s); s = Getchar()) x = x * 10 + s - 48;
15     return x * f;
16 }
17 
18 const int MAXN = 1000010;
19 
20 int n, f[MAXN]; long long ans;
21 int tot, Head[MAXN], ver[MAXN << 1], Next[MAXN << 1], edge[MAXN << 1];
22 
23 void add(int u, int v, int z)
24 {
25     ver[++tot] = v;
26     edge[tot] = z;
27     Next[tot] = Head[u];
28     Head[u] = tot;
29 }
30 
31 void dfs(int x, int fa)
32 {
33     f[x] = 1;
34     for(int i = Head[x]; i; i = Next[i])
35     {
36         int y = ver[i];
37         if(y == fa) continue;
38         dfs(y, x);
39         f[x] += f[y];
40         ans += 1ll * edge[i] * abs(n - f[y] - f[y]);
41     }
42 }
43 
44 int main()
45 {
46     n = Read();
47     for(int i = 1; i < n; ++i)
48     {
49         int u = Read(), v = Read(), z = Read();
50         add(u, v, z);
51         add(v, u, z);    
52     }
53     dfs(1, 0);
54     printf("%lld\n", ans);
55     return 0;
56 }

 

兔兔与蛋蛋游戏:

手玩几组数据可以发现,空格所经过的位置是不会重复的,而且这些位置都是白黑交错的,这让我们联想到二分图的增广路。

将起点和黑点设为左部点,白点设为右部点,那么每步操作就相当于是从一边走到另一边,且不会走到之前走过的点。

然后我们考虑什么情况下先手必败,如果当前的二分图存在一个最大匹配,且不包含起点,那么先手必败。

为什么呢,因为先手从起点出发,随便走一条非匹配边,然后后手一定可以找到一条匹配边,直到先手无路可走。

如果后手无法找到一条匹配边继续走的话,那么之前的路径就是一条增广路(非匹配边开始,非匹配边结束),这显然不符合之前最大匹配的条件。

那怎么判断存不存在一组不包含起点的最大匹配呢,我们强制当前点不选,如果它的匹配点仍然能找到新的匹配点,就说明有一种最大匹配不包含它。

代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 #define Get(i, j) ((i - 1) * m + j)
 5 const int dx[4] = {-1, 1, 0, 0};
 6 const int dy[4] = {0, 0, -1, 1};
 7 const int MAXN = 2010;
 8 const int MAXM = 10010;
 9 
10 int n, m, q, sx, sy, win[MAXN], mp[50][50];
11 int match[MAXN], visit[MAXN], ban[MAXN];
12 int tot, Head[MAXN], ver[MAXM], Next[MAXM];
13 int cnt, ans[MAXN];
14 
15 void add(int u, int v)
16 {
17     ver[++tot] = v;
18     Next[tot] = Head[u];
19     Head[u] = tot;
20 }
21 
22 int dfs(int x)
23 {
24     if(ban[x]) return 0;
25     for(int i = Head[x]; i; i = Next[i])
26     {
27         int y = ver[i];
28         if(ban[y]) continue;
29         if(!visit[y])
30         {
31             visit[y] = 1;
32             if(!match[y] || dfs(match[y]))
33             {
34                 match[y] = x;
35                 match[x] = y;
36                 return 1;
37             }
38         }
39     }
40     return 0;
41 }
42 
43 int main()
44 {
45     char str[50];
46     scanf("%d %d", &n, &m);
47     for(int i = 1; i <= n; ++i)
48     {
49         scanf("%s", str + 1);
50         for(int j = 1; j <= m; ++j)
51         {
52             if(str[j] == 'X') mp[i][j] = 1;
53             else if(str[j] == 'O') mp[i][j] = 0;
54             else
55             {
56                 mp[i][j] = 1;
57                 sx = i, sy = j;
58             }
59         }
60     }
61     for(int i = 1; i <= n; ++i)
62         for(int j = 1; j <= m; ++j)
63             for(int k = 0; k < 4; ++k)
64             {
65                 int x = i + dx[k], y = j + dy[k];
66                 if(x >= 1 && x <= n && y >= 1 && y <= m && mp[i][j] != mp[x][y])
67                     add(Get(i, j), Get(x, y));
68             }
69     for(int i = 1; i <= n; ++i)
70         for(int j = 1; j <= m; ++j)
71             if(mp[i][j])
72             {
73                 memset(visit, 0, sizeof(visit));
74                 dfs(Get(i, j));
75             }
76     scanf("%d", &q);
77     for(int i = 1; i <= (q << 1); ++i)
78     {
79         int u = Get(sx, sy);
80         ban[u] = 1;
81         if(match[u])
82         {
83             int v = match[u];
84             match[u] = match[v] = 0;
85             memset(visit, 0, sizeof(visit));
86             win[i] = !dfs(v);
87         }
88         scanf("%d %d", &sx, &sy);
89     }
90     for(int i = 1; i <= q; ++i)
91         if(win[(i << 1) - 1] && win[(i << 1)]) ans[++cnt] = i;
92     printf("%d\n", cnt);
93     for(int i = 1; i <= cnt; ++i) printf("%d\n", ans[i]);
94     return 0;
95 }

 

阿狸的打字机

先考虑暴力做法,我们把每个打印出来的串都加入AC自动机,然后对于每个询问直接匹配。

由于两个串都是AC自动机中的串,我们直接记下每个节点的父亲节点,然后从着$y$的结尾节点一直向上爬,在每个节点都跳$fail$指针,如果跳到了$x$的结尾节点就$++ans$即可。

发现对于两个相同的$y$,我们可以一次性处理,所以把询问离线下来排序处理,这样可以拿到$70$分。

我们的的问题是:$y$的每个节点沿着$fail$指针往上跳是否能到达$x$。

发现每个节点都只有一个$fail$指针,那我们把$fail$指针反过来连边,就得到了所谓的$fail$树。

那我们把上述问题也反过来,就是:$x$沿着$fail$指针往下跳能到达几个$y$的节点。

我们把$y$到根节点路径上的节点权值全部设为1,那么只需要求出$x$的子树和即可。(DFS序 + 树状数组)

即使是这样,对于每个$y$我们还是要一步步往上跳(设置权值),时间复杂度依然不能满足题目的要求。

我们慢在哪?每个串重复的前缀很多,对于离根节点比较近的那些点,我们重复设置了很多遍权值,从而严重降低了效率。

不如直接对$Trie$树进行一遍$DFS$,访问到的时候打一个+1,结束的时候打一个−1。

当一个点刚刚进入栈的时候,显然只有它到根节点路径上的节点被打了标记,此时我们就可以直接处理与这个节点相关的询问了。

代码:

  1 #include<bits/stdc++.h>
  2 using namespace std;
  3 
  4 #define lowbit(x) (x & (-x))
  5 const int MAXN = 100010;
  6 
  7 char str[MAXN];
  8 int n, m, tim, ids[MAXN], low[MAXN], dfn[MAXN];
  9 int tot, Head[MAXN], ver[MAXN], Next[MAXN];
 10 int ql[MAXN], qr[MAXN], ans[MAXN];
 11 
 12 void add(int u, int v)
 13 {
 14     ver[++tot] = v;
 15     Next[tot] = Head[u];
 16     Head[u] = tot;
 17 }
 18 
 19 void dfs(int u)
 20 {
 21     dfn[u] = ++tim;
 22     for(int i = Head[u]; i; i = Next[i]) dfs(ver[i]);
 23     low[u] = tim;
 24 }
 25 
 26 struct Query
 27 {
 28     int x, y, id, ans;
 29     bool operator < (const Query &a) const
 30     {
 31         return y < a.y;
 32     }
 33 }q[MAXN];
 34 
 35 struct Bit
 36 {
 37     int sum[MAXN], len;
 38     
 39     void add(int pos, int val)
 40     {
 41         for(; pos <= len; pos += lowbit(pos))
 42             sum[pos] += val;
 43     }
 44     
 45     int query(int pos)
 46     {
 47         int ans = 0;
 48         for(; pos; pos -= lowbit(pos)) ans += sum[pos];
 49         return ans;
 50     }
 51 }bit;
 52 
 53 struct AC
 54 {
 55     struct Node
 56     {
 57         int son[26], vis[26];
 58         int Next, fa, id;
 59     }t[MAXN]; int cnt;
 60     
 61     void add(char *s)
 62     {
 63         cnt = 1; int u = 1;
 64         int len = strlen(s + 1);
 65         for(int i = 1; i <= len; ++i)
 66         {
 67             if(s[i] >= 'a' && s[i] <= 'z')
 68             {
 69                 if(!t[u].son[s[i] - 'a']) t[u].son[s[i] - 'a'] = ++cnt, t[cnt].fa = u;
 70                 u = t[u].son[s[i] - 'a'];
 71             }
 72             else if(s[i] == 'B') u = t[u].fa;
 73             else ids[++n] = u, t[u].id = n;
 74         }
 75     }
 76     
 77     void build()
 78     {
 79         for(int i = 0; i <= 25; ++i) t[0].son[i] = 1;
 80         queue<int> q; q.push(1); t[1].Next = 0;
 81         while(!q.empty())
 82         {
 83             int x = q.front(); q.pop();
 84             for(int i = 0; i <= 25; ++i)
 85             {
 86                 if(!t[x].son[i]) t[x].son[i] = t[t[x].Next].son[i];
 87                 else
 88                 {
 89                     t[t[x].son[i]].Next = t[t[x].Next].son[i];
 90                     q.push(t[x].son[i]);
 91                 }
 92             }
 93         }
 94     }
 95     
 96     void dfs(int u)
 97     {
 98         bit.add(dfn[u], 1);
 99         if(t[u].id && ql[t[u].id])
100             for(int i = ql[t[u].id]; i <= qr[t[u].id]; ++i)
101                 q[i].ans = bit.query(low[ids[q[i].x]]) - bit.query(dfn[ids[q[i].x]] - 1);
102         for(int i = 0; i <= 25; ++i)
103             if(t[u].vis[i]) dfs(t[u].vis[i]);
104         bit.add(dfn[u], -1);
105     }
106 }ac;
107 
108 int main()
109 {
110     scanf("%s", str + 1);
111     ac.add(str);
112     for(int i = 1; i <= ac.cnt; ++i)
113         for(int j = 0; j <= 26; ++j) ac.t[i].vis[j] = ac.t[i].son[j];
114     ac.build();
115     for(int i = 2; i <= ac.cnt; ++i) add(ac.t[i].Next, i);
116     dfs(1);
117     scanf("%d", &m);
118     for(int i = 1; i <= m; ++i)
119     {
120         q[i].id = i;
121         scanf("%d %d", &q[i].x, &q[i].y);
122     }
123     sort(q + 1, q + 1 + m);
124     for(int i = 1, pos = 1; i <= m; i = pos)
125     {
126         ql[q[i].y] = i;
127         while(q[pos].y == q[i].y) ++pos;
128         qr[q[i].y] = pos - 1;
129     }
130     bit.len = tim;
131     ac.dfs(1);
132     for(int i = 1; i <= m; ++i) ans[q[i].id] = q[i].ans;
133     for(int i = 1; i <= m; ++i) printf("%d\n", ans[i]);
134     return 0;
135 }

 

posted @ 2019-04-22 20:49  Aegir  阅读(266)  评论(0编辑  收藏  举报