当前位置:网站首页>“蔚来杯“2022牛客暑期多校训练营3 ACFHJ
“蔚来杯“2022牛客暑期多校训练营3 ACFHJ
2022-07-28 15:27:00 【HeartFireY】
文章目录
- A.[Ancestor](https://ac.nowcoder.com/acm/contest/33188/A) LCA+暴力查询
- C.[Concatenation](https://ac.nowcoder.com/acm/contest/33188/C) 签到?
- F.[Fief](https://ac.nowcoder.com/acm/contest/33188/F) 点双连通分量
- H.[Hacker](https://ac.nowcoder.com/acm/contest/33188/H) SAM
- J.[Journey](https://ac.nowcoder.com/acm/contest/33188/J) 0-1最短路
A.Ancestor LCA+暴力查询
题目分析
给出两棵编号 1 − n 1-n 1−n的树 A , B A,B A,B, A , B A,B A,B树上每个节点均有一个权值,给出 k k k个关键点的编号 x 1 … x n x_1…x_n x1…xn,问有多少种方案使得去掉恰好一个关键点使得剩余关键点在树 A A A上 L C A LCA LCA的权值大于树 B B B上 L C A LCA LCA的权值。
处理出所有关键节点的前缀 L C A LCA LCA和后缀 L C A LCA LCA,然后枚举所有的关键节点求 L C A LCA LCA后 C h e c k Check Check计数即可。
Code
#include <bits/stdc++.h>
#pragma gcc optimize("O2")
#pragma g++ optimize("O2")
#define int long long
#define endl '\n'
using namespace std;
const int N = 2e5 + 10, MOD = 862118861;
int a[N], b[N], key[N];
vector<int> g1[N], g2[N];
struct LCA{
struct edge{
int to, len, next; } E[N];
int cnt, last[N], fa[N], top[N], deep[N], siz[N], son[N], val[N];
void addedge(int a, int b, int len = 0){
E[++cnt] = (edge){
b, len, last[a]}, last[a] = cnt;
}
void dfs1(int x){
deep[x] = deep[fa[x]] + 1;
siz[x] = 1;
for (int i = last[x]; i; i = E[i].next){
int to = E[i].to;
if (fa[x] != to && !fa[to]){
val[to] = E[i].len;
fa[to] = x;
dfs1(to);
siz[x] += siz[to];
if (siz[son[x]] < siz[to]) son[x] = to;
}
}
}
void dfs2(int x){
if (x == son[fa[x]]) top[x] = top[fa[x]];
else top[x] = x;
for (int i = last[x]; i; i = E[i].next)
if (fa[E[i].to] == x && fa[E[i].to] != E[i].to) dfs2(E[i].to);
}
void init(int root) {
dfs1(root), dfs2(root); }
int query(int x, int y){
for (; top[x] != top[y]; deep[top[x]] > deep[top[y]] ? x = fa[top[x]] : y = fa[top[y]]);
return deep[x] < deep[y] ? x : y;
}
}ta, tb;
int pa[N], pb[N], sa[N], sb[N];
inline void solve(){
int n = 0, k = 0; cin >> n >> k;
for(int i = 1; i <= k; i++) cin >> key[i];
for(int i = 1; i <= n; i++) cin >> a[i];
for(int i = 2; i <= n; i++){
int fa; cin >> fa;
ta.addedge(fa, i), ta.addedge(i, fa);
}
for(int i = 1; i <= n; i++) cin >> b[i];
for(int i = 2; i <= n; i++){
int fa; cin >> fa;
tb.addedge(fa, i), tb.addedge(i, fa);
}
ta.init(1), tb.init(1);
pa[1] = pb[1] = key[1], sa[k] = sb[k] = key[k];
for(int i = 2; i <= k; i++)
pa[i] = ta.query(pa[i - 1], key[i]), pb[i] = tb.query(pb[i - 1], key[i]);
for(int i = k - 1; i >= 1; i--)
sa[i] = ta.query(sa[i + 1], key[i]), sb[i] = tb.query(sb[i + 1], key[i]);
int ans = 0;
for(int i = 1; i <= k; i++){
int qa = 0, qb = 0;
if(i == 1){
qa = sa[i + 1], qb = sb[i + 1];
} else if(i == k){
qa = pa[i - 1], qb = pb[i - 1];
} else {
qa = ta.query(pa[i - 1], sa[i + 1]);
qb = tb.query(pb[i - 1], sb[i + 1]);
}
if(a[qa] > b[qb]) ans++;
}
cout << ans << endl;
}
signed main(){
ios_base::sync_with_stdio(false), cin.tie(0);
cout << fixed << setprecision(12);
int t = 1; //cin >> t;
while(t--) solve();
return 0;
}
C.Concatenation 签到?
题目分析
排序规则 A + B < B + A A + B < B + A A+B<B+A,排序后直接输出即可。
Code
#include <bits/stdc++.h>
#pragma gcc optimize("O2")
#pragma g++ optimize("O2")
#define int long long
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, MOD = 1e9 + 7;
string s[N];
inline void solve(){
int n = 0; cin >> n;
for(int i = 1; i <= n; i++){
cin >> s[i];
}
string ans;
sort(s + 1, s + 1 + n, [](string &a, string &b){
return (a + b) < (b + a); });
for(int i = 1; i <= n; i++) cout << s[i];
}
signed main(){
ios_base::sync_with_stdio(false), cin.tie(0);
cout << fixed << setprecision(12);
int t = 1; //cin >> t;
while(t--) solve();
return 0;
}
F.Fief 点双连通分量
题目分析
给定一个无向图,每次询问两点x, y,求是否存在一个n的排列,使得第一个元素为x,最后一个元素为y,且排列的任意一个前缀、任意一个后缀都连通。
对于询问 x , y x,y x,y,当且仅当添加一条边 ( x , y ) (x, y) (x,y)以后图是点双联通的,才为 Y e s Yes Yes。
队友 g k j j gkjj gkjj写的,后面再补,贴个代码
Code
#include <bits/stdc++.h>
#define int long long
#define endl '\n'
#define lowbit(x) (x&(-x))
#define ull unsigned long long
#define ll long long
#define pb push_back
using namespace std;
const string yes="YES\n",no="NO\n";
const int mod = 1000000007,N = 400005,inf=1e18;
const ull base=13331;
int qpow(int x,int y=mod-2,int mo=mod,int res=1){
for(;y;y>>=1,(x*=x)%=mo) if(y&1)(res*=x)%=mo;
return res;
}
const int M=1000050;
const ll INF=0x3f3f3f3f;
const ll MOD=1e9+7;
int n,m,fkcnt,q;
int head[N];
struct node {
int to,nxt;
}e[M];
int idx=0;
void add_edge(int u,int v){
e[idx].to=v;
e[idx].nxt=head[u];
head[u]=idx++;
}
int dfn[N],low[N],timestamp=0;
int stk[N],top=0;
int id[N],dcc_cnt;
int from[200005];
vector<int>dcc[N];//每个点双联通分量里面有哪些点
bool cut[N];
int root;
vector<int>p[300005];
void tarjan(int u){
dfn[u]=low[u]=++timestamp;
stk[++top]=u;
if(u==root &&head[u]==-1){
dcc_cnt++;
dcc[dcc_cnt].pb(u);
return ;
}
int cnt=0;
for(int i=head[u];~i;i=e[i].nxt){
int j=e[i].to;
if(!dfn[j]){
tarjan(j);
low[u]=min(low[u],low[j]);
if(dfn[u]<=low[j]){
cnt++;
if(u!=root||cnt>1){
cut[u]=true;
}
++dcc_cnt;
int y;
do{
y=stk[top--];
dcc[dcc_cnt].pb(y);
}while(y!=j);
dcc[dcc_cnt].pb(u);
/*p[dcc_cnt].push_back(u); p[u].push_back(dcc_cnt);*/
}
}
else {
low[u]=min(low[u],dfn[j]);
}
}
}
void build(){
for(int i=1;i<=dcc_cnt;i++){
for(auto x:dcc[i]){
from[x]=i+n;
}
}
for(int i=1;i<=n;i++){
if(cut[i])from[i]=i;
}
for(int u=1;u<=n;u++){
for(int i=head[u];~i;i=e[i].nxt){
int v=e[i].to;
if(from[u]!=from[v]){
p[from[u]].push_back(from[v]);
}
}
}
for(int i=1;i<=n+dcc_cnt;i++){
sort(p[i].begin(),p[i].end());
p[i].erase(unique(p[i].begin(),p[i].end()),p[i].end());
}
}
void solve(){
cin>>n>>m;
memset(head,-1,sizeof head);
for(int i=1;i<=m;i++){
int u,v;cin>>u>>v;
add_edge(u,v);
add_edge(v,u);
}
for(root=1;root<=n;root++){
if(!dfn[root]){
tarjan(root);
fkcnt++;
}
}
/*for(int i=1;i<=dcc_cnt;i++){ cout<<i<<":"; for(auto x:dcc[i]){ cout<<x<<" "; } cout<<endl; }*/
cin>>q;
if(n==2){
for(int i=1;i<=q;i++){
cout<<yes;
}
return;
}
if(fkcnt>1){
for(int i=1;i<=q;i++){
cout<<no;
}
return;
}
int cnt1=0,cnt2=0,cao=0,st=0,ed=0;;
build();
for(int i=1;i<=n+dcc_cnt;i++){
if(p[i].size()>2){
cao=1;
break;
}
else if(p[i].size()==1){
if(st)ed=i;
else st=i;
}
}
if(cao){
for(int i=1;i<=q;i++){
cout<<no;
}
return;
}
if(!ed){
for(int i=1;i<=q;i++){
cout<<yes;
}
return;
}
//cout<<st<<" "<<ed<<endl;
/*for(int i=1;i<=n;i++){ cout<<from[i]<<" \n"[i==n]; }*/
while(q--){
int u,v;
cin>>u>>v;
if(from[u]==st&&from[v]==ed||from[u]==ed&&from[v]==st){
cout<<yes;
}
else{
cout<<no;
}
}
}
void main_init(){
}
signed main(){
ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
cout<<fixed<<setprecision(12);
int t=1;
main_init();
//cin>>t;
while (t--)
solve();
}
H.Hacker SAM
题目分析
给定母串以及若干子串,子串长度固定,每个位置都有一个权值,要求在子串和母串的公共子串中找到一个连续区间,使得连续区间的权值和最大,求最大权值和。
首先对母串建立SAM,然后用线段树维护静态区间和的最大值,然后每次对插入的字符串:
我们设置两个变量 v , l v,l v,l,分别表示当前状态以及匹配长度,一开始 v = t 0 v=t_0 v=t0 且 l = 0 l=0 l=0,即匹配为空串。
现在我们来描述如何添加一个字符 T i T_{i} Ti 并为其重新计算答案:
- 如果存在一个从 v v v 到字符 T i T_{i} Ti 的转移,我们只需要转移并让 l l l 自增一。
- 如果不存在这样的转移,我们需要缩短当前匹配的部分,这意味着我们需要按照后缀链接进行转移:
v = link ( v ) v=\operatorname{link}(v) v=link(v)
与此同时,需要缩短当前长度。显然我们需要将 l l l 赋值为 len ( v ) \operatorname{len}(v) len(v)。
每次找到合法区间,直接线段树上查询并更新答案即可。
数据很水,不缩也能过,这里提供一组群友造的特殊样例:
输入:
11 11 1
aaaabbbaaaa
2 3 7 5 10 -2 0 10 2 4 0
aaaaaaaaaaa
输出:
25
Code
#include <bits/stdc++.h>
#pragma gcc optimize("O2")
#pragma g++ optimize("O2")
#define int long long
#define endl '\n'
using namespace std;
const int N = 2e5 + 10, MOD = 1e9 + 7;
const int INF = 1e9 + 7;
int ww[N];
#define ls rt << 1
#define rs rt << 1 | 1
#define lson rt << 1, l, mid
#define rson rt << 1 | 1, mid + 1, r
struct node{
int w, lw, rw, maxw;
node(){
w = 0;
lw = rw = maxw = -INF;
}
node operator+ (node b) const{
node c;
c.w = w + b.w;
c.lw = max(lw, w + b.lw);
c.rw = max(b.rw, b.w + rw);
c.maxw = max(max(maxw, b.maxw), rw + b.lw);
return c;
}
}tree[N << 2];
void build(int rt, int l, int r){
if(l == r){
tree[rt].w = tree[rt].lw = tree[rt].rw = tree[rt].maxw = ww[l];
return;
}
int mid = l + r >> 1;
build(lson), build(rson);
tree[rt] = tree[ls] + tree[rs];
}
node query(int rt, int l, int r, int L, int R){
if(l >= L && r <= R) return tree[rt];
int mid = l + r >> 1;
node b, c;
if(mid >= L) b = query(lson, L, R);
if(mid < R) c = query(rson, L, R);
return b + c;
}
struct state {
int len, link;
std::map<char, int> next;
};
const int MAXLEN = 100000;
state st[MAXLEN << 1];
int sz, last;
void sam_init() {
st[0].len = 0;
st[0].link = -1;
sz++;
last = 0;
}
void sam_extend(char c) {
int cur = sz++;
st[cur].len = st[last].len + 1;
int p = last;
while (p != -1 && !st[p].next.count(c)) {
st[p].next[c] = cur;
p = st[p].link;
}
if (p == -1) {
st[cur].link = 0;
} else {
int q = st[p].next[c];
if (st[p].len + 1 == st[q].len) {
st[cur].link = q;
} else {
int clone = sz++;
st[clone].len = st[p].len + 1;
st[clone].next = st[q].next;
st[clone].link = st[q].link;
while (p != -1 && st[p].next[c] == q) {
st[p].next[c] = clone;
p = st[p].link;
}
st[q].link = st[cur].link = clone;
}
}
last = cur;
}
int ql, qr;
int n, m, k;
int get(const string &T) {
int v = 0, l = 0, best = 0, bestpos = 0, ans = 0;
for (int i = 0; i < T.size(); i++) {
while (v && !st[v].next.count(T[i])) {
v = st[v].link;
l = st[v].len;
}
if (st[v].next.count(T[i])) {
v = st[v].next[T[i]];
l++;
}
int nowl = i - l + 1, nowr = i;
if(nowl <= nowr){
int res = query(1, 1, m, nowl + 1, nowr + 1).maxw;
ans = max(ans, res);
}
}
return ans;
}
inline void solve(){
cin >> n >> m >> k;
string a; cin >> a;
sam_init();
for (int i = 0; i < a.size(); i++) sam_extend(a[i]);
for(int i = 1; i <= m; i++) cin >> ww[i];
build(1, 1, m);
while(k--){
string s; cin >> s;
cout << get(s) << endl;
}
}
signed main(){
ios_base::sync_with_stdio(false), cin.tie(0);
cout << fixed << setprecision(12);
int t = 1; //cin >> t;
while(t--) solve();
return 0;
}
J.Journey 0-1最短路
题目分析
给定一个城市有若干十字路口,右转需要等红灯,直行、左转和掉头都需要,求起点到终点最少等几次红灯。
可以将每条路径视为点,十字路口处分情况连边,边权赋为 0 , 1 0,1 0,1,转化为 0 − 1 0-1 0−1最短路问题,然后直接跑 d i j k s t r a dijkstra dijkstra即可。
Code
#include <bits/stdc++.h>
#pragma gcc optimize("O2")
#pragma g++ optimize("O2")
#define int long long
#define endl '\n'
using namespace std;
const int N = 4e6 + 10;
#define pii pair<int, int>
#define mkp make_pair
#define fir first
#define sec second
int n = 0, cnt = 0;
int s1, s2, t1, t2;
vector<pii> g[N];
int dis[N];
struct node{
int fa, to, res, id;
const bool operator< (const node &x) const {
return res > x.res; }
};
priority_queue<node> pq;
void dijkstra(){
for(int i = 0; i < 4; i++){
auto &[v, k] = g[s1][i];
if(v == s2) pq.emplace(node{
s1, s2, 0, k});
}
while(pq.size()){
auto now = pq.top(); pq.pop();
if(now.to == 0 || dis[now.id] != -1) continue;
dis[now.id] = now.res;
for(int i = 0; i < 4; i++){
auto &[to, k] = g[now.to][i];
if(to == now.fa) pq.emplace(node{
now.to, g[now.to][(i + 1) % 4].fir, now.res, g[now.to][(i + 1) % 4].sec});
else pq.emplace(node{
now.to, g[now.to][(i + 1) % 4].fir, now.res + 1, g[now.to][(i + 1) % 4].sec});
}
}
}
void solve(){
cin >> n;
memset(dis, -1, sizeof(dis));
for(int i = 1; i <= n; i++){
for(int j = 0; j < 4; j++){
int v; cin >> v;
g[i].emplace_back(mkp(v, ++cnt));
}
}
cin >> s1 >> s2 >> t1 >> t2;
dijkstra();
for(int i = 0; i < 4; i++){
auto &[to, k] = g[t1][i];
if(to == t2) cout << dis[k] << endl;
}
}
signed main(){
ios_base::sync_with_stdio(false), cin.tie(0);
int t = 1; //cin >> t;
while(t--) solve();
return 0;
}
边栏推荐
- ANSA二次开发 - 抽中面的两种方法
- PHP计算坐标距离
- Practical development tutorial of software problem repair tracking system (Part 1)
- How to measure the vibrating wire sensor by vibrating wire acquisition module?
- R language ggplot2 visually draws line plots, and uses gghighlight package to highlight the lines that meet the combination judgment conditions in the line graphs (satisfies both condition a and b)
- PHP mb_ Substr Chinese garbled code
- 500million users, four years earlier than wechat... This app, which has been in operation for 15 years, will be permanently discontinued
- PHP获取小程序码,小程序带参数跳转
- A good start
- LwIP development | socket | DNS domain name resolution
猜你喜欢

关于web对接针式打印机问题,Lodop使用

Headline article_ signature

I'll show you a little chat! Summary of single merchant function modules

一大早支付宝来短信说你中“奖”了?处理服务器挖矿病毒 - kthreaddi

JS linked list 02

HyperMesh运行脚本文件的几种方法

MySQL view event status statements and modification methods

About the web docking pin printer, lodop uses

ANSYS二次开发 - MFC界面调用ADPL文件

LabVIEW Linx toolkit controls Arduino equipment (expansion-1)
随机推荐
Practical development tutorial of software problem repair tracking system (Part 1)
SCI scientific paper writing Growth Camp (full version)
跳表的实现
Detectron2 installation and testing
curl无输出返回空白或者null问题解决
在abaqus中使用PyQt设计GUI
Telecommuting can be easily realized in only three steps
ANSA二次开发 - Apps和ANSA插件管理
2021 Kent interview question 3
SDL2 简明教程(四):用 SDL_IMAGE 库导入图片
PHP获取小程序码,小程序带参数跳转
Numpy ndarray learning < II > miscellaneous records
HyperMesh运行脚本文件的几种方法
Darknet training yolov4 record
Wechat official account to obtain material list
Laser rangefinder non-contact surface crack monitor
PHP mb_ Substr Chinese garbled code
Baidu editor ueeditor, when editing too much content, the toolbar is not visible, which is not convenient for editing or uploading problems
疫情红利消失,「居家健身」泡沫消散
PHP计算坐标距离