tot:这场写了五题罚时674,铜牌区,第五题写的是凸包那题,New Energy Vehicle赛时没过,队友赛后队友补了,我就不补了,晕头。正赛最后一铜是5题罚时964。
C - Giving Directions in Harbin
思路:签到,按照题意随便模拟即可。
ll n;
vector<pair<char,int>> ans;
void solve(){
ans.clear();
cin>>n;
char face=0,init;
for(int i=1;i<=n;i++){
char way; cin>>way;
int x; cin>>x;
if(i==1) face=way,init=way,ans.emplace_back('Z',x);
else{
if(face=='S'){
if(way=='W') ans.emplace_back('R',0);
else if(way=='E') ans.emplace_back('L',0);
ans.emplace_back('Z',x);
face=way;
}
else if(face=='N'){
if(way=='W') ans.emplace_back('L',0);
else if(way=='E') ans.emplace_back('R',0);
ans.emplace_back('Z',x);
face=way;
}
else if(face=='E'){
if(way=='N') ans.emplace_back('L',0);
else if(way=='S') ans.emplace_back('R',0);
ans.emplace_back('Z',x);
face=way;
}
else if(face=='W'){
if(way=='S') ans.emplace_back('L',0);
else if(way=='N') ans.emplace_back('R',0);
ans.emplace_back('Z',x);
face=way;
}
}
}
cout<<ans.size()<<" "<<init<<"\n";
for(auto a:ans){
if(a.first=='Z') cout<<a.first<<" "<<a.second<<"\n";
else cout<<a.first<<endl;
}
}
M - Weird Ceiling
思路:队友写的。
ll n;
void solve(){
int n; cin >> n;
vector<int>ve;
for(int i=1;i<=n/i;i++){
if(n%i==0){
ve.push_back(i);
if(i!=n/i) ve.push_back(n/i);
}
}
sort(ve.begin(),ve.end());
ll ans=0;
for(int i=0,sz=ve.size();i<sz;i++){
if(i==sz-1){ans++; break;}
ans+=1ll*(ve[i+1]-ve[i])*(n/ve[i]);
}
cout << ans << "\n";
}
G - Welcome to Join the Online Meeting!
思路:随意以一个空闲的人作为发起会议的人,然后再check是否能全部人拉完即可。
ll n,m,k;
bool busy[200005];
vector<int> vct[200005];
bool vis[200005];
vector<vector<int>> ans;
void solve(){
cin>>n>>m>>k;
for(int i=1;i<=k;i++){
int x; cin>>x;
busy[x]=true;
}
for(int i=1;i<=m;i++){
int u,v; cin>>u>>v;
vct[u].emplace_back(v);
vct[v].emplace_back(u);
}
if(k==n){ cout<<"No"; return; }
int s=-1;
for(int i=1;i<=n;i++) if(!busy[i]){ s=i; break; }
queue<int> que;
que.emplace(s),vis[s]=1;
int cnt=1;
while((int)que.size()){
int from=que.front();
que.pop();
vector<int> temp;
temp.emplace_back(from);
for(auto v:vct[from]){
if(vis[v]) continue;
vis[v]=1,temp.emplace_back(v),cnt++;
if(!busy[v]) que.emplace(v);
}
if(temp.size()>1) ans.emplace_back(temp);
}
if(cnt!=n){ cout<<"No"; return; }
cout<<"Yes"<<"\n";
cout<<(int)ans.size()<<"\n";
for(auto a:ans){
cout<<a[0]<<" "<<(int)a.size()-1<<" ";
for(int i=1;i<(int)a.size();i++) cout<<a[i]<<" ";
cout<<"\n";
}
}
K - Farm Management
思路:先排序,再处理前缀和后缀数组,再二分即可。
ll n;
struct nod{
ll w,l,r;
}p[N];
int suml,sum;
int suf[100005],suf2[N];
void solve(){
ll m; cin >> n >> m;
for(int i=1;i<=n;i++){
cin >> p[i].w >> p[i].l >> p[i].r;
suml+=p[i].l,sum+=p[i].l*p[i].w;
}
sort(p+1,p+n+1,[](nod a,nod b){
if(a.w!=b.w) return a.w<b.w;
return a.l<b.l;
});
for(int i=n;i;i--){
suf[i]=suf[i+1]+p[i].r-p[i].l;
suf2[i]=suf2[i+1]+(p[i].r-p[i].l)*p[i].w;
}
ll ans=0;
for(int i=1;i<=n;i++){
ll lef=m-suml+p[i].l;
ll tsum=sum-p[i].l*p[i].w;
int l=i+1,r=n+1,res=0;
while(l<=r){
int mid=l+r>>1;
if(suf[mid]<=lef) res=mid,r=mid-1;
else l=mid+1;
}
ll lef2=lef-suf[res];
ans=max(tsum+suf2[res]+lef2*p[res-1].w,ans);
}
cout << ans;
}
B - Concave Hull
思路:赛时最后在另一台机子上面自己调了调过了,交了八发。在赛时这种几何题,如果有点把握感觉没问题的话,得大胆上机写。
外层求一次凸包,把第一次凸包的点去除之后,再求一次凸包. 然后找出第一次起点,双指针移动即可.
//#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define endl "\n"
typedef struct Point{
int x,y;
}Point;
Point operator-(Point a,Point b){ return {a.x-b.x,a.y-b.y}; }
__int128 operator^(Point a,Point b){ return a.x*b.y-a.y*b.x; }
__int128 cross(Point a,Point b,Point c){ return (b-a)^(c-a); }
Point point[100005];
Point pointTemp[100005];
int idx=0;
bool cmp(Point a,Point b){
if(a.x!=b.x) return a.x<b.x;
return a.y<b.y;
}
int n;
int stk1[100005];
int top1=0;
bool mark[100005];
void Andrew1(){
sort(point+1,point+n+1,cmp);
for(int i=1;i<=n;i++){
while(top1>1&&cross(point[stk1[top1-1]],point[stk1[top1]],point[i])<=0) top1--;
stk1[++top1]=i;
}
int tt=top1;
for(int i=n-1;i>=1;i--){
while(top1>tt&&cross(point[stk1[top1-1]],point[stk1[top1]],point[i])<=0) top1--;
stk1[++top1]=i;
}
}
int stk2[100005];
int top2=0;
void Andrew2(){
sort(pointTemp+1,pointTemp+idx+1,cmp);
for(int i=1;i<=idx;i++){
while(top2>1&&cross(pointTemp[stk2[top2-1]],pointTemp[stk2[top2]],pointTemp[i])<=0) top2--;
stk2[++top2]=i;
}
int tt=top2;
for(int i=idx-1;i>=1;i--){
while(top2>tt&&cross(pointTemp[stk2[top2-1]],pointTemp[stk2[top2]],pointTemp[i])<=0) top2--;
stk2[++top2]=i;
}
}
__int128 myabs(__int128 x){ return x<0?-x:x; }
__int128 S=0,ans=0;
void magic(){
int idx0=1;
__int128 mi=LONG_LONG_MAX;
// for(int i=1;i<=20;i++) mi*=10;
if(top2==1){
for(int i=1;i<top1;i++){
__int128 res=myabs(cross(point[stk1[i]],point[stk1[i+1]],pointTemp[1]));
ans=max(ans,S-res);
}
return;
}
for(int j=1;j<top2;j++){
__int128 res=myabs(cross(point[stk1[1]],point[stk1[2]],pointTemp[stk2[j]]));
if(res<mi) mi=res,idx0=j;
}
ans=max(ans,S-mi);
for(int i=1;i<top1;i++){
__int128 res=myabs(cross(point[stk1[i]],point[stk1[i+1]],pointTemp[stk2[idx0]]));
mi=res;
while(myabs(cross(point[stk1[i]],point[stk1[i+1]],pointTemp[stk2[(idx0+1-1)%(top2-1)+1]]))<mi){
mi=myabs(cross(point[stk1[i]],point[stk1[i+1]],pointTemp[stk2[(idx0+1-1)%(top2-1)+1]]));
idx0=(idx0+1-1)%(top2-1)+1;
}
ans=max(ans,S-mi);
}
}
void write(__int128 x){
if(x>9) write(x/10);
putchar(x%10+'0');
}
//思路:外层求一次凸包,把第一次凸包的点去除之后,再求一次凸包.
//然后找出第一次起点,双指针移动即可.
//Concave Hull
//https://codeforces.com/gym/105459/problem/B
void solve(){
cin>>n;
top1=0,top2=0,S=0,ans=0,idx=0;
for(int i=1;i<=n;i++) mark[i]=false;
for(int i=1;i<=n;i++) cin>>point[i].x>>point[i].y;
Andrew1();
if(top1-1==n){ cout<<"-1"<<endl; return; }
for(int i=1;i<=top1;i++) mark[stk1[i]]=true;
for(int i=1;i<=n;i++) if(!mark[i]) pointTemp[++idx]=point[i];
Andrew2();
for(int j=3;j<top1;j++) S+=cross(point[stk1[1]],point[stk1[j-1]],point[stk1[j]]);
magic();
if(ans==0){ cout<<"-1"<<"\n"; return; }
write(ans);
puts("");
}
int32_t main(){
// ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int t=1;
cin>>t;
while(t--) solve();
return 0;
}