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