G Horse Drinks Water
G-Horse Drinks Water_2024牛客暑期多校训练营4 (nowcoder.com)
这题就是初中学过的将军饮马问题,只需要走一遍x轴的 和一遍y轴 , 取小就可以了
void solve(){
int x1, y1, x2, y2;
cin >> x1 >> y1 >> x2 >> y2;
double ret1 = (x2 - x1) * (x2 - x1) + (y2 + y1) * (y2 + y1);
ret1 = sqrt(ret1);
double ret2= (x2 + x1) * (x2 + x1) + (y2 - y1) * (y2 - y1);
ret2 = sqrt(ret2);
ret1 = min(ret1, ret2);
printf("%.10lf\n", ret1);
}
I Friends
I-Friends_2024牛客暑期多校训练营4 (nowcoder.com)
对于这种类似的区间问题 , 不难想到,比如当我们有区间 [l,r],那么区间内的每对人都是好朋友,所以我们可以暴力的去对于每个人枚举他右边的连续区间 , 然后取一个交集即可
int n ,m ,r[N];
vector<int>g[N];
void solve(){
cin>>n>>m;
for(int i =1;i<=m;++i){
int u ,v;
cin>>u>>v;
g[u].push_back(v);
g[v].push_back(u);
}
for(int i =1;i<=n;++i)sort(all(g[i]));
for(int i =1;i<=n;++i){
int now = i;
r[i] = i;
for(auto to : g[i]){
if(to < now)continue;
if(to == now+1){
now++;
r[i] = now;
}
else break;
}
}
int ans = 0;
for(int i =n -1;i>=1;--i)r[i] = min(r[i] , r[i+1]);
for(int i =1;i<=n;++i)ans += (r[i] - i + 1);
cout<<ans;
}
C Sort4
这题很典。首先我们需要知道一个叫做置换环的东西。
置换环是用来求解数组排序元素间所需最小交换次数这类问题。
置换环思想:置换环将每个元素指向其排序后应在的位置,最终首位相连形成一个环(若数字在最终位置,则其自身成环),可知元素之间的交换只会在同一个环内进行,而每个环内的最小交换次数为 环上的数量-1
好了,那么我们可以先算出所有的环 , 对于每个环 , 如果环数量为4 , 那么一次操作即可完成 , 如果其大于4 , 就不止一次操作, 我们会发现,除了环内数量刚好为4 ,否则一次操作最大可以使3个数字排好序
int n , cnt;
int a[N];
bool vis[N];
void dfs(int x){
if(vis[x])return;
if(!vis[x]){
vis[x] = 1;
cnt++;
dfs(a[x]);
}
}
void solve(){
cin>>n;
for(int i =1;i<=n;++i){
cin>>a[i];
vis[i] = 0;
}
int ans = 0;
int tt = 0;
for(int i =1;i<=n;++i){
if(vis[i])continue;
cnt = 0;
dfs(i);
//找到这一组的cnt
while(cnt > 4){
cnt -=3 ,ans++;
}
if(cnt == 4)ans++;
else if(cnt ==1)continue;
else if(cnt == 2)tt++;
else if(cnt == 3)ans++;
}
cout<<ans + (tt / 2) + (tt %2 != 0)<<endl;
}
H Yet Another Origami Problem
H-Yet Another Origami Problem_2024牛客暑期多校训练营4 (nowcoder.com)
这题,我们可以先把最小的值想象成起点,最大的值想象成终点,然后,用中间的数值,慢慢的把最小的值折过去
int n;
void solve(){
cin>>n;
vector<int>a(n);
for(int i =0;i<n;++i)cin>>a[i];
sort(all(a));
int ans = 0;
for (int i = 1; i < n; i++) ans = __gcd(ans, a[i] - a[i - 1]);
cout << ans << "\n";
}
A LCT
A-LCT_2024牛客暑期多校训练营4 (nowcoder.com)
使用带权并查集,维护一下每个点在当前树的深度 , 和每个点的子树大小,当进来一个节点时,就合并,然后看 是原来的根的深度大 , 还是进来一个节点后,这个节点的子树深度+节点到根的距离大
int n;
int fa[N] , dis[N] , siz[N];
int find(int x){
if(x != fa[x]){
int t = fa[x];
fa[x] = find(fa[x]);
dis[x] += dis[t];
}
return fa[x];
}
void solve(){
cin>>n;
for(int i =1;i<=n;++i)fa[i] = i , siz[i] = 1 , dis[i] = 0;
for(int i =1;i<n;++i){
int u ,v , c;
cin>>u>>v>>c;
//u 是 v 的父亲
dis[v] = 1;
fa[v] = u;
find(v);
siz[find(u)] = max(siz[find(u)] , siz[v]+dis[v]);
cout<<siz[c]-1<<' ';
}
cout<<endl;
}