2024 China Collegiate Programming Contest (CCPC) Harbin Onsite (The 3rd Universal Cup. Stage 14: Har

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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值