p8584 探索未知

p8584 探索未知

【题目描述】

通道上有许多路牌。第 i 个路牌上写有一个分数 bi​、ai​​ 和一个分数运算符 + 或 −。

一开始,你的手上拿着一个数字 0。你沿着通道向后走。每走到一个路牌,会用手上的数和路牌上的分数,用路牌上的运算符号进行计算,并把得到的新数拿在手中(丢弃掉手中原来的数)。值得注意的是,如果你手中计算得到的数不是整数,则会保留既约分数的形式;否则直接保留整数形式。

现在你想知道,当你走到通道的末端时,手中拿着的数是多少?

【输入】

第 1 行共一个正整数 nn 表示通道内共有 n 个路牌。

第 2∼n+1 行每行三个正整数 ai​,bi​,opti​ 表示第 i 个路牌上写着的分数为 bi​、ai​​,运算符为 opti​。

其中,+,- 两种运算分别用 1,2 代替。

【输出】

共一行一个数。

若最终的结果可以保留为整数,则输出一个整数 ansans 表示结果。

结果可能出现负数,此时需要保留负号。例如,若结果为 −11451/4​,那么需要输出 -11451/4

对于 100% 的数据,保证  1≤n≤10^3,10000≤a≤1000, 10000<b≤1000,保证答案以及过程中全部数值(整数部分/分子/分母)不超过  2×10^9。

解题思路

这个题我刚开始是用约分的公式直接求的,每一步约分后再把公因数约掉。

这个题的数据范围:计算过程中数字的大小不超过  2×10^9,在分母相乘的过程中,最大的范围不会超过 4×10^18,所以要用 long long 的数据范围。

然后把负号考虑进来,当分子和分母同时为负数、分子是正数且分母是负数时,就要根据写分式的原则,把负号约掉或者提到分子前面。

这样子的思路是 50 分,可能在约分时没有处理得合适。

所以用辗转相乘法:

也就是求最大公约数和最小公倍数。

long long gec(long a,long b){//最大公倍数 
	if(b>0)
	return gec(b,a%b);
	else
	return a;
}
long long fun(long long a,long long b){//最小公倍数 
	return a*b/gec(a,b);
}

把最大公约数传入主函数,然后就是两个分式通分的过程,再根据每一行的最后一个数(运算符 c)算出当前的分子。然后在每次加完和减完后可以再通过最小公倍数将计算的结果化简。这一步如果省略也会出错!

代码如下:

#include<stdio.h>
#include<math.h>
long long mit(long a,long b){//最大公倍数 
	if(b>0)
	return mit(b,a%b);
	else
	return a;
}
long long mat(long long a,long long b){//最小公倍数 
	return a*b/mit(a,b);
}
int main()
{
	long long  son=0,mother=1;//初始化 
	long long n,a,b,c,i,j;
	scanf("%lld",&n);
	for(i=0;i<n;i++){
		scanf("%lld%lld%lld",&a,&b,&c);
		int k=mat(b,mother);//最小公倍数

		int d1=k/mother;
		int d2=k/b;

		if(c==1)
		son=d1*son+d2*a;
		else
		son=d1*son-d2*a;

		mother=k;
		int e=mit(abs(son),mother);//将得到的分式再化简
		son=son/e;
		mother=mother/e;
	}
	if(mother%son==0)
	printf("%lld\n",son/mother);
	else if(mother<0&&son<0)
	printf("%lld/%lld\n",-son,-mother);
	else if(mother<0&&son>0)
	printf("%lld/%lld\n",-son,-mother);
	else
	printf("%lld/%lld\n",son,mother);
	return 0;
}

01背包问题 

 二维 dp 数组:

#include<iostream>
#include<cmath>
using namespace std;
int dp[1005][1005];
int main(){
	int n,v,i,j,x,y;
	scanf("%d%d",&n,&v);
	for(j=1;j<=n;j++){
		scanf("%d%d",&x,&y);
		for(i=0;i<=v;i++){
			if(i<x)
			dp[i][j]=dp[i][j-1];
			else 
			dp[i][j]=max(dp[i][j-1],dp[i-x][j-1]+y);
		}
	}
	printf("%d\n",dp[v][n]);
}

一维 dp 数组:

#include<iostream>
#include<cmath>
using namespace std;
int dp[1005];
int main(){
	int i,j,x,y,v,n;
	scanf("%d%d",&n,&v);
	for(i=1;i<=n;i++){
		scanf("%d%d",&x,&y);
		for(j=v;j>0;j--){
			if(j>=x)
			dp[j]=max(dp[j],dp[j-x]+y);
		}
	}
	printf("%d\n",dp[v]);
	return 0;
}

p1706 全排列

 

#include<stdio.h>
int book[15];
int use[10];
void print(int n){
	for(int i=0;i<n;i++){
		printf("%5d",use[i]);
	}
	printf("\n");
}
void fun(int x,int n){
	if(x==n)
	{
		print(n);
		return ;
	}
	for(int i=1;i<=n;i++){
		if(book[i]==0)
		{
			book[i]=1;
			use[x]=i;
			fun(x+1,n);
			book[i]=0;
		}
	}
}
int main(){
	int n;
	scanf("%d",&n);
	fun(0,n);
	
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

明里灰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值