当前位置: 代码迷 >> 综合 >> hdu多校第五场题解(=100人)
  详细解决方案

hdu多校第五场题解(=100人)

热度:24   发布时间:2023-10-21 05:57:19.0

E - Everything Has Changed
利用余角定理算出弧度,然后乘以半径就行了。acos真牛逼!本来我以为相交还得分两种情况来计算,但实际上列了一个通式之后算出来的结果用acos转换成弧度之后它会自己变成正确的,因为acos的值域为[0,pi]

#include<bits/stdc++.h>
using namespace std;
const double PI=acos(-1.0);
const double eps=1e-9;
inline int sgn(double x)
{if(fabs(x)<eps)return 0;if(x>0)return 1;return -1;
}
int main()
{int T;scanf("%d",&T);while(T--){int m;double R;scanf("%d %lf",&m,&R);double ans=2*PI*R;while(m--){double x,y,r;scanf("%lf %lf %lf",&x,&y,&r);double d=sqrt(x*x+y*y);if(sgn(d-r-R)>=0||sgn(d-(R-r))<0)continue;if(sgn(d-(R-r))==0)ans+=2*PI*r;else{double yy=(d*d-R*R+r*r)/(2*d*r);double xx=(R*R+d*d-r*r)/(2*d*R);double delta1=acos(yy)*2;double delta2=acos(xx)*2;ans+=delta1*r;ans-=delta2*R;}}printf("%.7f\n",ans);}return 0;}

B - Beautiful Now
一开始写了一个假算法,感觉很正确,写博客的时候突然造了一个样例hack了。

void getmax(char *s)
{int len=strlen(s+1);int kk=k;for(int i=1; i<=len&&kk; i++){char it=s[i];int idx=-1;for(int j=len; j>i; j--){if(s[j]>it){it=s[j];idx=j;}}if(idx!=-1){swap(s[i],s[idx]);kk--;}}
}

这是那个假算法,虽然能得到最大的,但不一定是次数最小的,比如7699,按照这个就要花3次,实际上2次就行了。。唉。
正确答案也很简单,直接暴力就完事了。毕竟也就10!种状态

#include<bits/stdc++.h>
using namespace std;
string s;
bool cmp(char a,char b)
{return a>b;
}
int minans,maxans;
int k,len;int getnum()
{int res=0;for(int i=0;i<len;i++)res=res*10+s[i]-'0';return res;
}void dfs(int d,int c)
{int num=getnum();if(d==len-1||c==k){minans=min(minans,num);maxans=max(maxans,num);return;}minans=min(minans,num);maxans=max(maxans,num);for(int i=d+1;i<len;i++){if(d==0&&s[i]=='0')continue;swap(s[i],s[d]);dfs(d+1,c+1);swap(s[i],s[d]);}dfs(d+1,c);
}void solve()
{for(int i=0;i<len;i++){char it=s[i];int idx=-1;for(int j=i+1;j<len;j++){if(s[j]<it){if(i==0&&s[j]!='0'||i!=0){it=s[j];idx=j;}}}if(idx!=-1)swap(s[i],s[idx]);}
}int main()
{int T;std::ios::sync_with_stdio(false);cin>>T;while(T--){minans=1e9+10;maxans=0;cin>>s;cin>>k;len=s.size();if(k>=len){string b=s;sort(b.begin(),b.end(),cmp);solve();cout<<s<<' '<<b<<endl;continue;}dfs(0,0);cout<<minans<<' '<<maxans<<endl;}return 0;
}

G - Glad You Came
晕,一开始就想到了用线段树,然后用最小值最大值来进行剪枝,然而怎么写怎么T,原因是最后统计答案的时候还可以剪枝。。晕。。

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<cstring>
using namespace std;
const int maxn=1e5+5;
unsigned X,Y,Z;unsigned RNG61()
{X=X^(X<<11);X=X^(X>>4);X=X^(X<<5);X=X^(X>>14);unsigned W=X^(Y^Z);X=Y;Y=Z;Z=W;return Z;
}#define ls l,m,rt<<1
#define rs m+1,r,rt<<1|1
struct node
{int ma;int mi;int lazy;
}nodes[maxn<<2];void build(int l,int r,int rt)
{if(l==r){nodes[rt].ma=0;nodes[rt].mi=0;nodes[rt].lazy=0;return;}int m=l+r>>1;build(ls);build(rs);nodes[rt].lazy=0;nodes[rt].ma=0;nodes[rt].mi=0;
}void pushdown(int rt)
{if(nodes[rt].lazy){nodes[rt<<1].ma=nodes[rt].lazy;nodes[rt<<1].lazy=nodes[rt].lazy;nodes[rt<<1|1].ma=nodes[rt].lazy;nodes[rt<<1|1].lazy=nodes[rt].lazy;nodes[rt<<1].mi=nodes[rt].lazy;nodes[rt<<1|1].ma=nodes[rt].lazy;nodes[rt].lazy=0;}
}void pushup(int rt)
{nodes[rt].ma=max(nodes[rt<<1].ma,nodes[rt<<1|1].ma);nodes[rt].mi=min(nodes[rt<<1].mi,nodes[rt<<1|1].mi);
}void update(int L,int R,int C,int l,int r,int rt)
{if(nodes[rt].mi>=C)return;if(L<=l&&r<=R){if(l==r){nodes[rt].ma=max(nodes[rt].ma,C);nodes[rt].mi=nodes[rt].ma;return;}if(nodes[rt].ma<=C){nodes[rt].ma=C;nodes[rt].mi=C;nodes[rt].lazy=C;return;}}pushdown(rt);int m=l+r>>1;if(L<=m)update(L,R,C,ls);if(R>m)update(L,R,C,rs);pushup(rt);
}
int a[maxn];
void query(int l,int r,int rt)
{if(nodes[rt].ma==nodes[rt].mi||l==r){for(int i=l;i<=r;i++)a[i]=nodes[rt].ma;return;}int m=l+r>>1;pushdown(rt);query(ls);query(rs);
}int main()
{int T;scanf("%d",&T);while(T--){int n,m;scanf("%d %d %u %u %u",&n,&m,&X,&Y,&Z);build(1,n,1);for(int i=1;i<=m;i++){int tmp1=RNG61()%n+1;int tmp2=RNG61()%n+1;int v=RNG61()%(1<<30);int l=min(tmp1,tmp2),r=max(tmp1,tmp2);update(l,r,v,1,n,1);//cout<<l<<' '<<r<<' '<<v<<' '<<query(1,1,n,1)<<' '<<query(2,1,n,1)<<endl;}long long ans=0;query(1,n,1);for(int i=1;i<=n;i++){ans=ans^(1LL*i*a[i]);}printf("%lld\n",ans);}return 0;}