杭电第五场题解

1010 Bragging Dice

两个人玩明牌的 “吹牛骰子” 游戏,求先手和后手谁赢。 一个人投出的点数全部不同时,视为没有点数。

​ 只有当一个塞子都没有的情况下后手必胜,否则先手必胜

#include<bits/stdc++.h>
using namespace std;

int n;
int a[10],b[10];

int main(){
    int T;
	scanf("%d",&T);
	while(T--){
		scanf("%d",&n);
		int x;
		memset(a,0,sizeof(a));
		memset(b,0,sizeof(b));
		bool flag1,flag2;
		flag1=flag2=1;
		for(int i=1;i<=n;i++) {
            scanf("%d",&x);
            if(a[x]) flag1=0;
            a[x]++;
		}
		for(int i=1;i<=n;i++) {
            scanf("%d",&x);
            if(b[x]) flag2=0;
            b[x]++;
		}
		if(flag1&&flag2) printf("Just a game of chance.\n");
		else printf("Win!\n");
	}
    return 0;
}

 1003 Slipper

​ 给定一棵树和树上边权,每次可以走树上的边,也可以花费 p 的代价向上或向下跳 k层。求点 s到点 t 的最短路。

汇总点给对应深度的所有点建一条长度为0的单向边,然后每个点给深度跟他绝对值差k的点对应的汇总点建一条长度为p的单向边,最后跑一遍dij

#include<bits/stdc++.h>
using namespace std;
template <typename tn>void read(tn &n){
    tn f=1,t=0;char ch=getchar();
    while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    while (isdigit(ch)) t=t*10+ch-'0',ch=getchar();
    n=f*t;
}
inline void out(int x){
	if(x>9)out(x/10);
	putchar(x%10+'0');
}
priority_queue< pair<int,int> > q;
const int Maxn=1001000;
int Ver[Maxn],Edge[Maxn],Next[Maxn],head[Maxn],Dep[Maxn],n,T,tot,k,p,s,t,max_dep=0;;
long long Dist[Maxn];
bool Visited[Maxn];
void add(int x,int y,int z){
	Ver[++tot]=y,Edge[tot]=z,Next[tot]=head[x],head[x]=tot;
}
void walk(int x){
	for(register int i=head[x];i;i=Next[i]){
		int y=Ver[i];
		if(Dep[y]>Dep[x]+1){
			Dep[y]=Dep[x]+1;
			max_dep=max(max_dep,Dep[y]);
			walk(y);
		}
	}
}
bool cmd(int a,int b){
	return a<b;
}
int main(){
	read(T);
	while(T--){
		memset(head,sizeof(head),0);
		tot=0;
		read(n);
		for(register int i=1;i<n;++i){
			int u,v,w;
			read(u),read(v),read(w);
			add(u,v,w);
			add(v,u,w);
		}
		read(k),read(p);
		read(s),read(t);
		Dep[1]=1;
		for(register int i=2;i<=n;++i)Dep[i]=n+1;
		walk(1);
		for(register int i=1;i<=n;++i){
			if(Dep[i]>k)add(i,n+Dep[i]-k,p);
			if(Dep[i]+k<=max_dep)add(i,n+Dep[i]+k,p);
			add(n+Dep[i],i,0);
		}
		for(register int i=1;i<=n+max_dep;++i)Dist[i]=1000000000001;
		Dist[s]=0;
		memset(Visited,false,sizeof(Visited));
		q.push(make_pair(0,s));
		while(q.size()){
			int x=q.top().second;
			if(x==t)break;
			q.pop();
			if(Visited[x])continue;
			Visited[x]=true;
			for(register int i=head[x];i;i=Next[i]){
				int y=Ver[i],z=Edge[i];
				if(Dist[y]>Dist[x]+z){
					Dist[y]=Dist[x]+z;
					q.push(make_pair(-Dist[y],y));
				}
			}
		}
		cout<<Dist[t]<<endl;
	}
    return 0;
}

1012.Buy Figurines

​ n个人m个窗口买手办,每个人有对应到的时间和花费的时间,问最后一个人离开的时间。

考虑时刻ai第i个人到达商店时,如何快速查询最短并且编号最小的队伍,可以用set维护队伍的信息,又考虑到每个人的开始时刻和结束时刻是不同的,可以用一个优先队列来维护时间轴的信息。先按照时间轴的顺序,模拟 商店入队和出队的情况,进而求出每个人的购买雷电将军人偶的开始时间和结束时间,最后一个人的结束时间即为 本题所求答案。
#include<bits/stdc++.h>
using namespace std;
using ll = long long;
const int N=2e5+5;
template <typename tn>void read(tn &n){
    tn f=1,t=0;char ch=getchar();
    while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
    while (isdigit(ch)) t=t*10+ch-'0',ch=getchar();
    n=f*t;
}
inline void out(int x){
	if(x>9)out(x/10);
	putchar(x%10+'0');
}
struct Data{
	int arrival,spent; 
}data[N];
struct Timeline{
	ll time; 
	int type,id;
	Timeline(ll _time=0,int _type=0,int _id=0) :
	time(_time),type(_type),id(_id) {}
	// type = 0 for departure, type = 1 for arrival
	bool operator < (const Timeline &t) const{
		if(time!=t.time)return time>t.time;
		return type>t.type;
	}
};
priority_queue<Timeline> Tl;
struct Queue{
	int num,id;
	Queue(int _num=0,int _id=0) :
	num(_num),id(_id){}
	bool operator < (const Queue &t) const{
		if(num==t.num)return id<t.id;
		return num<t.num;
	}
}q[N];
set<Queue> Que;
int T,n,m,Queue_select[N];
ll ans,Last[N];
int main(){
	read(T);
	while(T--) {
		read(n),read(m);
		for(int i=1;i<=n;++i)
		read(data[i].arrival),read(data[i].spent);
		for(int i=1;i<=n;++i)
		Tl.push(Timeline(data[i].arrival, 1, i));
		Que.clear();
		for(int i=1;i<=m;++i){
			q[i].num=0,q[i].id=i;
			Que.insert(q[i]);
			Last[i]=0;
		}
		while(!Tl.empty()){
			auto tl=Tl.top();
			Tl.pop();
			ll time=tl.time; 
			int type=tl.type,id=tl.id;
			if(type==0){
				int qid=Queue_select[id];
				Que.erase(Queue(q[qid].num,q[qid].id));
				Que.insert(Queue(--q[qid].num,q[qid].id));
			}
			else{
				auto que=*Que.begin();
				int num=que.num,qid=que.id;
				Que.erase(que);
				Queue_select[id] = qid;
				if(num==0)Last[qid]=time+data[id].spent;
				else Last[qid]+=data[id].spent;
				q[qid].num++; 
				que.num++;
				Que.insert(que);
				Tl.push(Timeline(Last[qid],0,id));
			}
		}
		ans=0;
		for(int i=1;i<=m;++i) 
		ans=max(ans,Last[i]);
		printf("%lld\n",ans);
	}	
	return 0;
} 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值