20260717比赛总结
猜结论还是挺好玩的。
A. 弹弓
人类智慧。寻找前 \(1200\) 和后 \(1200\) 个的最小代价可以通过。赛后测了最小大约 \(400\) 也可。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
struct node{int x,y,t;}arr[N];
pair<int,int> p[N],q[N];
int n,m;
int main(){
scanf("%d %d",&n,&m);
for(int i=1,x,y,t;i<=n;++i) scanf("%d %d %d",&x,&y,&t),p[i]={x,i},q[i]={y,i},arr[i]={x,y,t};
sort(p+1,p+n+1),sort(q+1,q+n+1);
while(m--){
int a,b,mn=2e9,k;scanf("%d %d",&a,&b);
int it1=lower_bound(p+1,p+n+1,make_pair(a,0))-p,it2=lower_bound(q+1,q+n+1,make_pair(b,0))-q;
for(int i=max(1,it1-1500);i<=min(n,it1+1200);++i) k=p[i].second,mn=min(mn,abs(a-arr[k].x)+abs(b-arr[k].y)+arr[k].t);
for(int i=max(1,it2-1500);i<=min(n,it2+1200);++i) k=q[i].second,mn=min(mn,abs(a-arr[k].x)+abs(b-arr[k].y)+arr[k].t);
printf("%d\n",min(mn,abs(a-b)));
}
}
B. 牛棚
动态维护树的直径。可惜我不会,打了暴力。
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,q,res;
int dis[N];
vector<int> vec[N];
void dfs(int u,int f){
if(dis[u]>=dis[res]) res=u;
for(auto v:vec[u]){
if(v==f) continue;
dis[v]=dis[u]+1;
dfs(v,u);
}
}
int main(){
scanf("%d",&q);
while(q--){
char op[3];int x;scanf("%s %d",op,&x);
if(op[0]=='B'){++n;if(~x) vec[n].push_back(x),vec[x].push_back(n);}
else res=0,dis[x]=0,dfs(x,0),printf("%d\n",dis[res]);
}
}
C. 体操运动员
猜到结论了。答案为
\[2-n+\sum_{i=1}^{n-1}2^{\gcd(n,i)}
\]
但只剩 \(7\) min 了。于是打了 \(O(n)\) 暴力。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=1e6+5;
const ll mod=1e9+7;
int n;
ll sum,d[N];
ll qpow(ll n,ll m){
ll res=1;
for(;m;m>>=1,n=n*n%mod) if(m&1) res=res*n%mod;
return res;
}
ll phi(ll x){
double res=x;
for(ll i=2;i*i<=x;++i){
if(!(x%i)){
res*=(1-1.0/i);
while(!(x%i)) x/=i;
}
}
if(x!=1) res*=(1-1.0/x);
return res;
}
int main(){
scanf("%d",&n);vector<int> vec;
for(int i=1;i*i<=n;++i){
if(n%i==0){
vec.push_back(i);
if(i!=1&&n!=i*i) vec.push_back(n/i);
}
}
sort(vec.begin(),vec.end());
for(auto i:vec) sum+=phi(n/i)*qpow(2,i)%mod;
printf("%lld",(sum+mod-n%mod+2)%mod);
}

浙公网安备 33010602011771号