前言:
一场通过乱搞获得如下成绩的比赛。
\(T1:\)
思路:
一场情况超级复杂(bushi)的大模拟(应该可以这么叫吧?)直接先这样这样,在那样那样,最后在叽里呱啦就好了。
嘿嘿,开个玩笑嘛。首先,我们知道一定至少从\(S'\)跳到\(S\)到\(T\)的那条链上,这样我们可以就\(S'\)跳到\(S\)到\(T\)的链上的位置大致分为两大种情况进行讨论:第一种,跳到\(S\)和\(T\)的\(lca\)上。此时\(S\)和\(T\)在同一个子树上;第二种,跳到\(S'\)和\(T\)或\(S'\)和\(S\)的\(lca\)上,此时\(S\)和\(T\)在不同一个子树上。然后再分为几个小的情况再讨论就好了。
代码:追逐游戏 (chase)
$code time$
#include<iostream>
#include<algorithm>
using namespace std;
const int N=2e5+5;
int n,q,u,v,cnt,s,t,ss,point,dep[N],fa[N][20],head[N];
struct node{int to,nxt;}e[N<<1];
inline void add(int x,int y){e[++cnt].to=y;e[cnt].nxt=head[x];head[x]=cnt;
}//建边
inline int find(int x,int y){if(x==y) return x;if(dep[x]>dep[y]){for(int i=19;i>=0;i--) if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];if(x==y) return x;}else if(dep[x]<dep[y]){for(int i=19;i>=0;i--) if(dep[fa[y][i]]>=dep[x]) y=fa[y][i];if(x==y) return x;}for(int i=19;i>=0;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];return fa[x][0];
}//倍增求lca
inline void dfs(int x,int daddy){dep[x]=dep[daddy]+1;fa[x][0]=daddy;for(int i=1;i<=19;i++) fa[x][i]=fa[fa[x][i-1]][i-1];for(int i=head[x];i;i=e[i].nxt){int y=e[i].to;if(y!=daddy) dfs(y,x);}
}//固定树的形态
inline int getpoint(int s,int e,int t){int lca=find(s,e);if(t<=dep[s]-dep[lca]){point=s;for(int i=19;i>=0;i--) if(dep[fa[point][i]]>=dep[s]-t) point=fa[point][i];}//S翻不过去lca else{point=e;for(int i=19;i>=0;i--) if(dep[fa[point][i]]>=dep[e]-(dep[s]+dep[e]-2*dep[lca]-t)) point=fa[point][i];}//S翻过去了lca return point;
}//一个小分讨
inline int getdis(int x,int y){return dep[x]+dep[y]-2*dep[find(x,y)];
}//求两点之间的距离
int main(){freopen("chase.in","r",stdin);freopen("chase.out","w",stdout);ios::sync_with_stdio(false);cin>>n>>q;for(int i=1;i<n;i++) cin>>u>>v,add(u,v),add(v,u);dfs(1,0);while(q--){cin>>s>>t>>ss;int lcs=find(ss,s),lst=find(s,t),lct=find(ss,t),stop,st,ct;if(dep[lct]<=dep[lst]&&dep[lcs]<=dep[lst]) stop=lst;else if(dep[lcs]<dep[lct]) stop=lct;else stop=lcs;st=getdis(s,stop);//S到该点的时间 ct=getdis(ss,stop);//S'到该点的时间 if(st==ct) cout<<st<<" "<<stop<<'\n';//相等直接输出 else if(st<ct) cout<<ct+getdis(stop,t)<<" "<<t<<'\n';//S'大的话就只能追到T点了 else{//S到该点的时间长 所以S'还可以从该点再向S点的方向追 int delta=(st-ct)>>1;//小学数学:相向而行问题 cout<<st-delta<<" "<<getpoint(s,t,st-delta)<<'\n';}}return 0;
}
\(T2:\)统计(st)
思路:
给\([1,m-1]\)每个值赋一个随机值,然后给\(m\)赋为\([1,m-1]\)所赋值的总和的相反数,然后求一边前缀和,若前缀和为0,则证明他们出现的次数一样多(再往后就没听懂了😛)
代码:
点击查看代码
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=1e6+10;
int T,a[N],b[N],sum[N],n,m,ans,tot;
mt19937 mrd(time(0));
signed main(){
// freopen("st.in","r",stdin);
// freopen("st.out","w",stdout);cin>>T;while(T--){cin>>n>>m;ans=0,tot=0;for(int i=1;i<=n;i++) cin>>a[i];for(int i=1;i<m;i++) b[i]=mrd(),tot+=b[i];b[m]=-tot;//赋值 for(int i=1;i<=n;i++) sum[i]=sum[i-1]+b[a[i]];//前缀和 sum[++n]=0;//这后面的就不会了 sort(sum+1,sum+n+1);for(int i=1;i<=n;i++){int j=i;while(sum[j+1]==sum[j]&&j<n) j++;int num=j-i+1;ans+=num*(num-1)/2;i=j;}printf("%lld\n",ans);}return 0;
}
\(T3:\) 软件工程(se)
思路:
凭借乱搞做法喜提96高分,正确性无法保证 (因为根本没有) 。我们观察样例可得,我们可以将线段按顺序排序,然后将\(n-k+1\)条短的边分到一组,然后剩下的边分别单独一组。然后数据范围告诉我们\(k=2\)是一种特殊情况,然后当\(k=2\)时,将线段按\(l\)的大小排序,然后把它分成两段,跟第一条线段相交的分为第一组,其余的为第二组,然后你就可以 愉快 稀里糊涂的\(AC\)掉此题了。
代码:
点击查看代码
#include<iostream>
#include<algorithm>
#define int long long
using namespace std;
const int N=5200;
int n,k,ans,res,l,r=1e6+5;;
struct node{int l,r;}a[N];
inline bool cmp(node a,node b){return (a.r-a.l)<(b.r-b.l);}
inline bool css(node a,node b){return a.l<b.l;}
signed main(){
// freopen("se.in","r",stdin);
// freopen("se.out","w",stdout);ios::sync_with_stdio(false);cin>>n>>k;for(int i=1;i<=n;i++) cin>>a[i].l>>a[i].r;if(k>=n){for(int i=1;i<=n;i++) ans+=a[i].r-a[i].l;cout<<ans<<'\n';return 0;//特判 }sort(a+1,a+1+n,cmp);//排序 for(int i=1;i<=n-k+1;i++){l=max(l,a[i].l);r=min(r,a[i].r);}ans+=max(r-l,0ll);for(int i=n-k+2;i<=n;i++) ans+=a[i].r-a[i].l;l=0,r=1e6+5; if(k==2){sort(a+1,a+1+n,css);l=a[1].l;r=a[1].r;for(int i=2;i<=n;i++){if((a[i].l>=l&&a[i].l<=r)||(a[i].r>=l&&a[i].r<=r)){l=max(l,a[i].l);r=min(r,a[i].r);}else{res+=r-l;l=a[i].l;r=a[i].r;}}res+=r-l;ans=max(ans,res);}cout<<ans;return 0;
}//代码挺简单的 就不写注释了哈
\(T4:\) 命运的X(x)
目前无人会做哈,可以给你们粘一个学长的链,自己看去吧