有那么几个题挺有意思的 记录一下
题目
VOJ
D - Fix Wiring
题意: 给\(n \le 100\) 个点, \(\frac{n(n - 1)}{2}\) 条边, 和他们的边权,
让你来连边, 求最小和最大的最小生成树权值
最小的显然, 让我们看最大的
考虑这个题和这个 非常像,
考虑目前已经选出一颗最小生成树, 新加入一个点和与他相连的边,
你要让一条边成为最小生成树中的边,
就要让他与最小生成树中点的边权都大于这条边
于是我们只需要把边权从大到小排序, 然后按照\(n - 1, n - 2, \cdots, 1\) 的个数分组,
每组找最小值作为最小生成树的边就可以了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 #include <iostream> #include <cstring> #include <cstdio> #include <cstdlib> #include <algorithm> #define MAXN (100) #define LL long long using namespace std;int n, a[MAXN * MAXN + 5 ];LL ans; bool cmp (int x, int y) { return x > y; }int main () { scanf ("%d" , &n); for (int i = 1 ; i <= (n - 1 ) * n / 2 ; i++) scanf ("%d" , &a[++a[0 ]]); sort (a + 1 , a + a[0 ] + 1 , cmp); for (int i = a[0 ]; i >= a[0 ] - n + 2 ; i--) ans += a[i]; printf ("%lld " , ans); ans = 0 ; for (int i = n - 1 , j = 0 ; i >= 1 ; i--) ans += a[j += i]; printf ("%lld" , ans); return 0 ; }
P - 加工零件
1号要做原料当且仅当a与1的距离的奇偶性与L相同, 且小于L
dijkstra跑一跑就好了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <queue> #define MAXN (100000) #define pii pair<int, int> using namespace std;struct edg { int from, to, next; } b[MAXN * 2 + 5 ]; struct cmp { bool operator () (const pii& x, const pii& y) { return x.second > y.second; } }; int g[MAXN + 5 ], cntb, n, m, dis[MAXN][2 ], q;bool vis[MAXN + 5 ][2 ];void ade (int fr, int t) { b[++cntb] = {fr, t, g[fr]}; g[fr] = cntb; } void dijk () { priority_queue<pii, vector<pii>, cmp> q; q.push (make_pair (1 , 0 )); memset (dis, 0x7f , sizeof (dis)); memset (vis, false , sizeof (vis)); dis[1 ][0 ] = 0 ; while (!q.empty ()) { pii now = q.top (); q.pop (); if (vis[now.first][now.second & 1 ]) continue ; vis[now.first][now.second & 1 ] = true ; for (int i = g[now.first]; i; i = b[i].next) if (dis[b[i].to][(now.second & 1 ) ^ 1 ] > now.second + 1 ) dis[b[i].to][(now.second & 1 ) ^ 1 ] = now.second + 1 , q.push (make_pair (b[i].to, dis[b[i].to][(now.second & 1 ) ^ 1 ])); } } int main () { scanf ("%d%d%d" , &n, &m, &q); for (int i = 1 , xi, yi; i <= m; i++) scanf ("%d%d" , &xi, &yi), ade (xi, yi), ade (yi, xi); dijk (); for (int i = 1 , a, l; i <= q; i++) scanf ("%d%d" , &a, &l), puts ((dis[a][l & 1 ] <= l) ? "Yes" : "No" ); return 0 ; }
R - 括号树
显然这个树的条件屁用没有
考虑链上咋做,
令f[n]
为以n
为结尾的合法括号串个数,
显然f[n] = (s[n - 1] == ')') ? (f[x] + 1) : 0
,
其中x
是n
前面与n
最近的使[x, n]
是合法括号串的数
我一直在考虑怎么转换成\((1,
-1)\) 序列来做, 似乎得用线段树之类的
后来抄题解才知道直接用栈就行了, 左括号入栈其编号就行,
右括号出栈栈顶就是x
了
我是傻逼
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #include <stack> #define LL long long #define MAXN (500000) using namespace std;struct edg { int from, to, next; } b[MAXN + 5 ]; int g[MAXN + 5 ], cntb, n, a[MAXN + 5 ], fa[MAXN + 5 ];bool vis[MAXN + 5 ];char s[MAXN + 5 ];LL f[MAXN + 5 ], ans; stack<int > gary, pek; void ade (int fr, int t) { b[++cntb] = {fr, t, g[fr]}; g[fr] = cntb; } void dfs (int now) { if (~a[now]) gary.push (now); else if (!gary.empty ()) { vis[now] = true ; pek.push (gary.top ()); f[now] = f[fa[gary.top ()]] + 1 ; gary.pop (); } for (int i = g[now]; i; i = b[i].next) dfs (b[i].to); if (~a[now]) gary.pop (); if (vis[now]) gary.push (pek.top ()), pek.pop (); } void calc (int now, LL xans) { ans ^= (xans + f[now]) * now; for (int i = g[now]; i; i = b[i].next) calc (b[i].to, xans + f[now]); } int main () { memset (vis, false , sizeof (vis)); scanf ("%d" , &n); scanf ("%s" , s); for (int i = 1 ; i <= n; i++) a[i] = (s[i - 1 ] == '(' ) ? 1 : -1 ; for (int i = 2 ; i <= n; i++) scanf ("%d" , &fa[i]), ade (fa[i], i); dfs (1 ); calc (1 , 0ll ); printf ("%lld" , ans); return 0 ; }
By Cansult