【题目描述】
通道上有许多路牌。第 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
解题思路
这个题我刚开始是用约分的公式直接求的,每一步约分后再把公因数约掉。
这个题的数据范围:计算过程中数字的大小不超过 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
#include
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;i0)
printf("%lld/%lld\n",-son,-mother);
else
printf("%lld/%lld\n",son,mother);
return 0;
}
二维 dp 数组:
#include
#include
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
一维 dp 数组:
#include
#include
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;
}
#include
int book[15];
int use[10];
void print(int n){
for(int i=0;i