我解决的:B(1 WA)、I、J、A(3 WA)、D(1 WA,1 TLE)。
没看的:无。
旁观的:C、F、K、G、H。
看了但没做出来的:E、L。
简单题,略。
简单题,略。
简单题,略。
最短路,略。本来应该一次过的题目,但写错了好几个地方,简直丢人。
题意:给定几个简单多边形,计算其面积的和。
计算几何模板题,丢人的在于我还不会写(板子也没带)。
题意:有一些可以对栈进行的操作。栈中的元素有两种:不可分割,称为简单类型(Simple);由两个元素构成的二元组,称为复杂类型(Complex)。给定两个操作序列,问对于任意一个只包含简单类型元素的、足够长的栈,这两个操作序列是否等价。等价定义为:要么经两个操作序列分别操作后,得到的两个结果相等,要么两个操作序列在该栈上均失败。
本题就是模拟,先构造一个比较长的栈,每个元素有一个不同的编号,然后两个操作序列分别模拟即可。
最后判断二元组相等的时候要用一些 Hash,否则会 TLE。
题意:给定一张有向图和一个点 T T T,问有哪些点满足其有一条边连向 T T T,且其只能经这条边到达 T T T。
我们先取出那些有一条边连向 T T T 的点,称为关键点。显然答案是其的子集。
随后扔掉关键点指向 T T T 的边,再构建反图。我们希望对每一个关键点,看看是否有另一个关键点到它的路径。
为此,我们可以对每一个关键点 u u u 维护一个集合 S ( u ) S(u) S(u),表示可以到达 u u u 的关键点的集合。我们保证这个集合大小不超过 2,因为只要达到了 2 就表明 u u u 不是答案了。
随后以每一个关键点为起点 DFS 即可。时间复杂度除了最后排序外为线性。
#include
using namespace std;
int read(){
int f = 1, x = 0;
char c = getchar();
while (c < '0' || c > '9'){if(c == '-') f = -f; c = getchar();}
while (c >= '0' && c <= '9')x = x * 10 + c - '0', c = getchar();
return f * x;
}
int n, m, T;
int to[100005], nxt[100005], at[100005] = {0}, cnt = 0;
vector<int> keyp, ans;
int S[100005][2] = {0};
void dfs(int cur, int st){
if (S[cur][1] || S[cur][0] == st || S[cur][1] == st)
return ;
if (!S[cur][0]) S[cur][0] = st;
else S[cur][1] = st;
for (int i = at[cur]; i; i = nxt[i])
dfs(to[i], st);
}
int main(){
n = read(), m = read(), T = read() + 1;
for (int i = 1; i <= m; ++i){
int u = read() + 1, v = read() + 1;
if (v == T) keyp.push_back(u);
else {
to[++cnt] = u, nxt[cnt] = at[v], at[v] = cnt;
}
}
for (int x: keyp) dfs(x, x);
for (int x: keyp){
if (!S[x][1]) ans.push_back(x);
}
printf("%u\n", ans.size());
sort(ans.begin(), ans.end());
for (int x: ans)
printf("%d\n", x - 1);
return 0;
}
题意:给定一个二叉树关于点权的中序遍历,满足每一个点的点权均不小于父亲节点,问具有这种中序遍历的不同形态的二叉树有多少个。
看样例 1,可以看出,如果点权互不相同,那么结果是唯一确定的。因为每次可以找到最小权的点,其一定是当前子树的根,然后在其左右递归下去即可。
那么如果有多个最小权的节点呢?显然,它们应该是连在一起的,否则就破坏了题目的条件。如果这些节点有 t t t 个,那么这些节点形成的树的数目就是 Catalan t \operatorname{Catalan}_t Catalant。而对于被最小权节点分割开的区间,它们的答案只要在此基础上乘起来就行了。
这种分治的做法很直观,但是时间复杂度难以降下来。实际上可以用一些单调栈的做法,考虑每一个点权之前,离其最近的、不大于它的点权。然后考虑后者是否将前者隔断。具体可以看代码理解。
#include
#define MOD 1000000007
using namespace std;
int read(){
int f = 1, x = 0;
char c = getchar();
while (c < '0' || c > '9'){if(c == '-') f = -f; c = getchar();}
while (c >= '0' && c <= '9')x = x * 10 + c - '0', c = getchar();
return f * x;
}
int n, a[1000005], inv[1000005], catalan[1000005];
int st[1000005], top, lft[1000005], cnt[1000005] = {0};
void init(){
n = read();
for (int i = 1; i <= n; ++i)
a[i] = read();
inv[1] = 1;
for (int i = 2; i <= n + 1; ++i)
inv[i] = 1ll * (MOD - MOD / i) * inv[MOD % i] % MOD;
catalan[0] = catalan[1] = 1;
for (int i = 2; i <= n; ++i){
catalan[i] = 1ll * catalan[i - 1] * inv[i] % MOD;
catalan[i] = 1ll * catalan[i] * (2 * i - 1) % MOD;
catalan[i] = 1ll * catalan[i] * (2 * i) % MOD;
catalan[i] = 1ll * catalan[i] * inv[i + 1] % MOD;
}
}
void solve(){
a[0] = -1;
st[top = 1] = 0;
for (int i = 1; i <= n; ++i){
while (a[st[top]] > a[i])
--top;
lft[i] = st[top];
st[++top] = i;
}
// 用 cnt 计算位于同一个子树内的相同点权个数
int res = 1;
for (int i = 1; i <= n; ++i){
if (a[lft[i]] < a[i]){
res = 1ll * res * catalan[cnt[a[i]]] % MOD;
cnt[a[i]] = 1;
}else{
++cnt[a[i]];
}
}
for (int i = 0; i <= 1000000; ++i)
res = 1ll * res * catalan[cnt[i]] % MOD;
printf("%d\n", res);
}
int main(){
init();
solve();
return 0;
}
题意:给了一个神秘的随机数生成器,求前 N N N 个数中有多少是偶数。
由抽屉原理,必然存在一个循环节。可以先用 Floyd 判圈算法算出进入循环节前要有多少个数,以及循环节有多长。然后每 1 0 7 10^7 107 个数打一个表,暴力计算即可。
题意:有 S S S 种动物,有 L L L 个不同种动物间的友好关系(没有传递性)。给定一个长为 N N N 的动物队列,相邻的动物如果有友好关系就可以交换位置。问可以得到的字典序最小的队列。
由于关系无传递性,不能用并查集维护。
注意到位置 i i i 和 j j j 的动物不可交换,且 i < j i < j i<j,那么无论如何, i i i 都会在 j j j 前面。因此可以连一条 i i i 到 j j j 的边,然后跑一个字典序最小的拓扑排序即可。
问题在于这样边的数目会很多,是 O ( N 2 ) O(N^2) O(N2) 的。我们改进一下,对于每一个位置 j j j,如果前面有不可与其交换的动物,那就让最靠后的那个连向 j j j。于是边数下降到了 O ( N S ) O(NS) O(NS),可以通过。
总时间复杂度为 O ( N S + N log N ) O(NS + N \log N) O(NS+NlogN)。
#include
using namespace std;
int S, L, N;
string s1, s2;
vector<string> vec;
unordered_map<string, int> mp;
bool ok[205][205] = {0};
int que[100005], last_pos[205] = {0};
vector<int> G[100005];
int du[100005] = {0}, ans[100005];
priority_queue<pair<int, int>, vector<pair<int, int> >,
greater<pair<int, int> > > pq;
void init(){
ios::sync_with_stdio(false);
cin.tie(0);
cin >> S >> L >> N;
for (int i = 1; i <= S; ++i){
cin >> s1;
vec.push_back(s1);
}
sort(vec.begin(), vec.end());
for (int i = 1; i <= S; ++i){
mp[vec[i - 1]] = i;
}
for (int i = 1; i <= L; ++i){
cin >> s1 >> s2;
int u = mp[s1], v = mp[s2];
ok[u][v] = ok[v][u] = true;
}
for (int i = 1; i <= N; ++i){
cin >> s1;
int id = mp[s1];
que[i] = id;
for (int j = 1; j <= S; ++j){
if (!ok[j][id] && last_pos[j]){
G[last_pos[j]].push_back(i);
++du[i];
}
}
last_pos[id] = i;
if (!du[i]) pq.push(make_pair(id, i));
}
}
void solve(){
int tot = 0;
while (!pq.empty()){
int h = pq.top().second;
pq.pop();
ans[++tot] = h;
for (int v: G[h]){
--du[v];
if (!du[v]) pq.push(make_pair(que[v], v));
}
}
for (int i = 1; i < N; ++i)
cout << vec[que[ans[i]] - 1] << ' ';
cout << vec[que[ans[N]] - 1] << '\n';
}
int main(){
init();
solve();
return 0;
}
待补。。。
待补。。。