A - Engines Atcoder 4900
题目大意:n个点,任意几个点组合后得到的点距离原点的最远距离。
题解:极角排序:https://blog.csdn.net/qq_39942341/article/details/79840394
利用极角排序,将这些点看成与原点相作用的向量,然后根据平行四边行法则,两向量之间的角度相差越小,其复合得到的向量的长度越长
#include<bits/stdc++.h> using namespace std; const int N=1E5+7; struct stu{ double a,b; bool friend operator <(const stu &x,const stu &y){ return atan2(x.b,x.a)<atan2(y.b,y.a); } }arr[N]; int nxt[N]; int main(){ int n; cin>>n; for(int i=1;i<=n;i++) cin>>arr[i].a>>arr[i].b; for(int i=1;i<=n;i++) nxt[i]=i+1; nxt[n]=1; sort(arr+1,arr+1+n); double ans=0; for(int i=1;i<=n;i++){//以每个点为起始点,遍历一圈后回到起始点,同时记录大小 double dx=arr[i].a; double dy=arr[i].b; ans=max(ans,arr[i].a*arr[i].a+arr[i].b*arr[i].b); for(int j=nxt[i];j!=i;j=nxt[j]){ dx+=arr[j].a; dy+=arr[j].b; ans=max(ans,dx*dx+dy*dy); } } printf("%.15lf\n",sqrt(ans)); return 0; }
B - Consecutive Integers
规律
#include<iostream> using namespace std; int main(){ int n,k; cin>>n>>k; cout<<n-k+1<<endl; return 0; }
规律题。错一位取余相加
#include<iostream> using namespace std; typedef long long ll; int main() { ll n; cin>>n; cout<<n*(n-1)/(ll)2<<endl; return 0; }
D - Shortest Path on a Line
题目大意:输入一个范围。从L[i]~R[i],在这个范围内的两个数(s<t)s到t的权值为C,求点1到点N的最短距离
题解:从i到i-1建一个权值为0的反向边,这样就能使得一个范围L[i]~R[i]任意两点之间的距离为C。不足之处,仅限与求从S到T(S<T)的情况。
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll INF=1E18+7; const ll N=1E5+7; ll n,m; struct stu{ ll a,b; bool friend operator <(const stu &x,const stu &y){ return x.b>y.b; } }; vector <stu >ve[N]; bool mark[N]; ll dp[N]; void djstrea(){ priority_queue<stu>que; que.push({1,0}); dp[1]=0; while(que.size()){ stu x=que.top(); que.pop(); if(mark[x.a]) continue ; mark[x.a]=1; for(ll i=0;i<ve[x.a].size();i++){ ll dx=ve[x.a][i].a; ll dy=ve[x.a][i].b; if(dp[dx]>dp[x.a]+dy){ dp[dx]=dp[x.a]+dy; que.push({dx,dp[dx]}); } } } } int main(){ cin>>n>>m; ll x,y,z; for(ll i=1;i<=n;i++) { ve[i].push_back({i-1,0}); } for(ll i=0;i<=n;i++) dp[i]=INF; for(ll i=1;i<=m;i++){ cin>>x>>y>>z; ve[x].push_back({y,z}); } djstrea(); if(dp[n]==INF) cout<<-1<<endl; else cout<<dp[n]<<endl; return 0; }
E - Counting of Trees
思维
注意1为根节点,D[i]指的是1到i的距离。所以这里0的个数必须为1,而且只能是d[1]=0,其他的地方不能出现0。然后我们在找到最大的权值,权值为i的点只能连接在权值为i-1上,因此共有arr[i-1]^arr[i]种可能;
#include<iostream> #include<cstdio> using namespace std; typedef long long ll; const int N=1e5+7; const ll mod=998244353; ll arr[N]; ll ksm(ll x,ll y){ ll res=1; while(y){ if(y&1) res=res*x%mod; x=x*x%mod; y>>=1; } return res%mod; } int main() { ll n; cin>>n; ll x; ll sum=1; ll s=0; for(ll i=1;i<=n;i++){ cin>>x; if(i==1&&x!=0) sum=0; arr[x]++; s=max(x,s); } for(ll i=s;i>=0;i--){ if(arr[i]==0) sum=0; if(i>1){ sum=sum*ksm(arr[i-1],arr[i])%mod; } } if(arr[0]>1) sum=0; cout<<sum%mod<<endl; return 0; }
F - Monsters Battle Royale
模拟一下过程,始终的大的减去小的。所以答案应该为这些数的__gcd
#include<bits/stdc++.h> using namespace std; int main() { int n; cin>>n; int g; for(int i=1;i<=n;i++) { int x; cin>>x; if(i==1){ g=x; } else { g=__gcd(g,x); } } cout<<g<<endl; return 0; }
G - Powerful Discount Tickets
把所有的票都用完,并且每次都要给最贵的用,所有用优先队列
#include<iostream> #include<queue> #include<cstdio> using namespace std; typedef long long ll; priority_queue<ll >que; int main() { ll n,m; cin>>n>>m; ll x; for(ll i=1;i<=n;i++){ cin>>x; que.push(x); } ll ans=0; while(m--){ ll x=que.top(); que.pop(); x=x/2; que.push(x); } while(que.size()){ ans+=que.top(); que.pop(); } cout<<ans<<endl; return 0; }
H - Attack Survival
模拟一下就好了
#include<bits/stdc++.h> using namespace std; const int N=1E5+7; int arr[N]; int main(){ int n,k,q; cin>>n>>k>>q; for(int i=1;i<=q;i++){ int x; cin>>x; arr[x]++; } for(int i=1;i<=n;i++){ int a=k-(q-arr[i]); if(a<=0) cout<<"No"<<endl; else cout<<"Yes"<<endl; } return 0; }
I - Lower
模拟
#include<iostream> #include<cstdio> using namespace std; const int N=1E5+7; int arr[N]; int main() { int n; cin>>n; for(int i=1;i<=n;i++) cin>>arr[i]; int ans=0; int sum=0; for(int i=n-1;i>=1;i--){ if(arr[i]>=arr[i+1]) ans++; else ans=0; sum=max(ans,sum); } cout<<sum<<endl; return 0; }
J - Kleene Inversion
求一下单个区间内的逆序对的个数x,在求两个复合区间的逆序对的个数y,然后x*k+y*(k-1)*k/2,,取余的时候要注意,会爆longlong。
求逆序对用到了归并排序
#include<bits/stdc++.h> using namespace std; const int N=5e5+7; typedef long long ll; const ll mod=1e9+7; ll arr[N]; ll mark[N]; ll right_[N]; ll ans=0; void merage_sort(ll l,ll r){ if(l>=r) return ; ll mid=(l+r)/2; merage_sort(l,mid); merage_sort(mid+1,r); ll i=l,j=mid+1,k=l; while(i<=mid&&j<=r){ if(arr[i]<=arr[j]){ right_[k++]=arr[i++]; } else { right_[k++]=arr[j++]; ans+=1ll*mid-i+1; } } while(i<=mid) right_[k++]=arr[i++]; while(j<=r) right_[k++]=arr[j++]; for(ll i=l;i<=r;i++) arr[i]=right_[i]; } int main(){ ll n,k; cin>>n>>k; for(ll i=1;i<=n;i++){ cin>>arr[i]; mark[i]=arr[i]; } ll ans1; merage_sort(1,n); ans1=ans; ll ans2=0; for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(arr[i]>arr[j]) ans2++; } } cout<<(k%mod*ans1%mod+k%mod*(k-1)/2%mod*ans2%mod)%mod<<endl; return 0; }
K - Two Contests
题目连接:https://atcoder.jp/contests/agc040/tasks/agc040_b
大佬题解:https://blog.csdn.net/duanghaha/article/details/102892233
题意:有N个问题,每个问题可以由编号L~R之间的人完成,有两个集合S和T,将N个问题放入两个集合中,使得交集和最大
题解与证明
首先找到lmost,与rmin,当区间rmin与lmost在同一个集合中,此时答案为rmin-lmost+1+most_width(最大宽度)
当二者不再同一个集合中时,那么答案为 max((rmin-x+1)+(y-lmost+1))其中x为l[i],y为r[j]注意x与y不可以是同一个区间的左右边界。
现在已经确定了集合S中有lmost,所以,T中一定有rmin。。问题转换为一个数组,,两个参数,将这个数组划分为来年部分。使得两部分的和最大
#include<bits/stdc++.h> using namespace std; const int INF=1e9+7; const int N=1E5+7; int l[N],r[N]; int arr[N]; struct stu{ int a,b; bool friend operator <(const stu &x,const stu &y){ return x.a>y.a; } }s[N]; int main() { int n; cin>>n; int lmax=0,rmin=INF,width=0; for(int i=1;i<=n;i++){ cin>>l[i]>>r[i]; if(l[i]>=lmax) lmax=l[i]; if(r[i]<=rmin) rmin=r[i]; width=max(width,r[i]-l[i]+1); } int sum=max(rmin-lmax+1,0)+width; for(int i=1;i<=n;i++){ s[i].a=max(0,rmin-l[i]+1); s[i].b=max(0,r[i]-lmax+1); } sort(s+1,s+1+n); arr[n]=s[n].b; for(int i=n-1;i>=1;i--) arr[i]=min(arr[i+1],s[i].b); int ans=0; for(int i=1;i<=n-1;i++) ans=max(ans,s[i].a+arr[i+1]); cout<<max(ans,sum)<<endl; return 0; }
M - AB Substrings
记录一下以b开头的字符串的数目,记录一下以a结尾的字符串的数目,在记录以b开头a结尾的字符串的数目
#include<bits/stdc++.h> using namespace std; typedef long long ll; ll aend=0,bhead=0,ab=0; int main() { int n; cin>>n; string s; ll ans=0; for(int i=1;i<=n;i++){ cin>>s; int x=s.size(); for(int j=0;j<x-1;j++){ if(s[j]=='A'&&s[j+1]=='B') ans++; } if(s[0]=='B'&&s[x-1]=='A') ab++; if(s[0]=='B') bhead++; if(s[x-1]=='A') aend++; } aend-=ab; bhead-=ab; if(aend==0&&bhead==0){ if(ab==0||ab==1) cout<<ans<<endl; else cout<<ans+ab-1<<endl; } else if(aend==0||bhead==0){ cout<<ans+ab<<endl; } else if(aend!=0&&bhead!=0){ cout<<ans+min(aend,bhead)+ab<<endl; } return 0; }