算法竞赛进阶指南学习day6

CH0701国王游戏


题目:

恰逢 H 国国庆,国王邀请 n 位大臣来玩一个有奖游戏。首先,他让每个大臣在左、右手上面分别写下一个整数,国王自己也在左、右手上各写一个整数。然后,让这 n 位大臣排成一排,国王站在队伍的最前面。排好队后,所有的大臣都会获得国王奖赏的若干金币,每位大臣获得的金币数分别是:排在该大臣前面的所有人的左手上的数的乘积除以他自己右手上的数,然后向下取整得到的结果。
国王不希望某一个大臣获得特别多的奖赏,所以他想请你帮他重新安排一下队伍的顺序,使得获得奖赏最多的大臣,所获奖赏尽可能的少。注意,国王的位置始终在队伍的最前面。

对于 20%的数据,有 1≤ n≤ 10,0 < a、b < 8;
对于 40%的数据,有 1≤ n≤20,0 < a、b < 8;
对于 60%的数据,有 1≤ n≤100;
对于 60%的数据,保证答案不超过 109;(所以必须用高精)
对于 100%的数据,有 1 ≤ n ≤1,000,0 < a、b < 10000


思路:

(参考https://www.luogu.com.cn/blog/league/solution-p1080)

令大臣左手是l,右手是r,则经过推导可得出按l*r进行从小到大排序就可以得出答案;对于一个人,他的位置改变不会对他后面的人产生影响,因为对于后面的人来说还是乘了那几个数,只是顺序不同;再记得打个高精


代码:

#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
#include<algorithm>
#include<string>
#include<cstring>
using namespace std;
struct man{
	int l,r;
}a[1010];
int le[10010],ans[10010],ls[10010];//ls存储了除法的结果 
bool cmp(man A,man B){
	return A.l*A.r<B.l*B.r;
}
void chu(int num){//高精除底精 
	memset(ls,0,sizeof(ls));
	int x=0;
	for(int i=10009;i>=0;i--){
		x=x*10+le[i];
		ls[i]=x/num;
		x%=num;
	}
}
void cheng(int num){//高精乘低精 
	for(int i=10008;i>=0;i--){
		le[i]*=num;
	}
	for(int i=0;i<10009;i++){
		le[i+1]+=le[i]/10;
		le[i]%=10;
	}
}
bool bigger(){
	for(int i=10009;i>=0;i--){
		if(ls[i]>ans[i]) return 1;
		if(ls[i]<ans[i]) return 0;
	}
	return 0;
}
void cp(){
	for(int i=0;i<10010;i++){
		ans[i]=ls[i];
	}
}
int main(){
	int n;
	cin>>n;
	for(int i=0;i<=n;i++){
		cin>>a[i].l>>a[i].r ;
	}
	sort(a+1,a+n+1,cmp);
	le[0]=1;
	for(int i=0;i<=n;i++){
		chu(a[i].r);
		if(bigger()) cp() ;
		cheng(a[i].l) ;
	}
	int i=10010;
	while(ans[i]==0){
		i--;
		
	}
	for(;i>=0;i--){
		cout<<ans[i];
	}
	return 0;
}

CH0802

题目:lyd学会了使用扑克DIY占卜。方法如下:一副去掉大小王的扑克共52张,打乱后均分为13堆,编号1~13,每堆4张,其中第13堆称作“生命牌”,也就是说你有4条命。这里边,4张K被称作死神。
初始状态下,所有的牌背面朝上扣下。
流程如下:
1.抽取生命牌中的最上面一张(第一张)。
2.把这张牌翻开,正面朝上,放到牌上的数字所对应编号的堆的最上边。(例如抽到2,正面朝上放到第2堆牌最上面,又比如抽到J,放到第11堆牌最上边,注意是正面朝上放)
3.从刚放了牌的那一堆最底下(最后一张)抽取一张牌,重复第2步。(例如你上次抽了2,放到了第二堆顶部,现在抽第二堆最后一张发现是8,又放到第8堆顶部.........)
4.在抽牌过程中如果抽到K,则称死了一条命,就扔掉K再从第1步开始。
5.当发现四条命都死了以后,统计现在每堆牌上边正面朝上的牌的数目,只要同一数字的牌出现4张正面朝上的牌(比如4个A),则称“开了一对”,当然4个K是不算的。
6.统计一共开了多少对,开了0对称作"极凶",1~2对为“大凶”,3对为“凶”,4~5对为“小凶”,6对为“中庸”,7~8对“小吉”,9对为“吉”,10~11为“大吉”,12为“满堂开花,极吉”。

直接模拟!!!

#include<iostream>
#include<cstdio>
#include<cmath>
#include<vector>
#include<algorithm>
#include<string>
#include<queue>
#include<cstring>
using namespace std;
int up[13];
int change(char a) {
	if(a>='2'&&a<='9') {
		return (a-'0');
	}
	if(a=='0') return int(10);
	if(a=='J') return int(11);
	if(a=='Q') return int(12);
	if(a=='K') return int(13);
}
deque<int> dui[15];
int main() {
	char a;
	for(int i=1; i<=13; i++) {
		for(int j=0; j<4; j++) {
			cin>>a;
			//cout<<a[i][j]<<endl;
			dui[i].push_back(change(a)) ;
		}
	}

	int n;
	while(dui[13].size()) {
		n=dui[13].front() ;
		dui[13].pop_front();
		while(n!=13) {
			up[n]++;
			int l=n;
			n=dui[n].back();
			dui[l].pop_back();
		}
	}
	int ans=0;
	for(int i=1; i<13; i++) {
		if(up[i]>=4) {
			ans++;
		}
	}
	cout<<ans;
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值