由于今天出山,因此没有报名比赛,只是看题口胡
T1
随便手玩一下样例发现每次就是削去一个半径差为2的环,然后就是大模拟把感觉挺难写的
T2
分析策略知道一定是能合并就合并,一开始想
树形dp两次但是发现并不会写,然后不难发现至多会合并 $n-1$ 次,本能想起超级钢琴的套路,然后就是使每次折叠在折点被统计,就是对于每个点记一个map<pair<int,int>,int>,维护的是是否存在与这个点相邻的且点值为x,边值为y的点,然后如果把一个节点存进来的时候发现可以合并,那么就把维护的这个节点编号和新加进来的点一起压进某一个队列或者堆栈里头,像超级钢琴那样每次取出一个点,然后合并,合并的时候用启发式合并来合并map,然后时间复杂度是 $O(n\cdot logn\cdot logn)$ 的。
好像听说被出题人专门卡了,离大谱
写了一般的启发式合并。。。。
#include <bits/stdc++.h>
#define int long long
using namespace std;
inline int read(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch))f^=ch=='-',ch=getchar();
while(isdigit(ch))x=x*10+(ch^48),ch=getchar();
return f?x:-x;
}
const int N=5e5+5;
int n,,a[N],dfn[N],id[N],dfntot;
priority_queue<pair<int,int>> q;
vector<int> G[N],W[N];
map<pair<int,int>,int> col[N];
void dfs1(int u,int fa){
dfn[u]=++dfntot;
id[u]=u;
for(int i=0;i<G[u].size();++i){
int v=G[u][i];
if(v==fa)continue;
dfs1(v,u);
}
for(int i=0;i<G[u].size();++i){
int v=G[u][i],w=W[u][i];
if(col[u].find({a[v],w})!=col[u].end()){
q.push({v,col[u][{a[v],w}]});
}
else col[u][{a[v],w}]=v;
}
}
void merge(int x,int y){//merge x and y
int _x=id[x],_y=id[y];
if(col[_x].size()<col[_y].size())swap(_x,_y);
map<pair<int,int>,int>::iterator it;
for(it=col[_y].begin();it!=col[_y].end();it++){
int c=*it->first.first;
int w=*it->first.second;
int v=*it->second;
if(col[_x].find({c,w})!=col[_x].end()){
q.push({v,col[_x][{c,w}]});
}
}
id[x]=id[y]=_x;
col[_y].clear();
}
int ans=0;
signed main(){
n=read();
for(int i=1;i<=n;++i){
a[i]=read();
}
for(int i=1;i<n;++i){
int x=read(),y=read(),z=read();
G[x].push_back(y);
G[y].push_back(x);
W[x].push_back(z);
W[y].push_back(z);
}
dfs1(1,0);
while(q.size()){
pair<int,int> x=q.top();
q.pop();
q
}
}
T3
做法第一步很容易想到吧,就是枚举因子,然后就不会了(正常人谁做字符串想哈希啊),然后听说正解就是哈希,人麻了,还被出题人怒斥了。
T4
正解肯定不会,但是发现 $O(3^n\cdot n)$ 的就是一个高维前缀和什么的