[日常训练] tty的方程

问题描述

  • tgopknight正在教sc捉数学题,今天他教的是加法和乘法和乘方。
  • 唐沟铺的tgopknight果然神,他是这样教导的:
    • “加法是基本的四则运算之一,它是指将两个或者两个以上的数、量合起来,变成一个数、量的计算。
    • 乘法是指将相同的数加起来的快捷方式。其运算结果称为积。从哲学角度解析,乘法是加法的量变导致的质变结果。
    • n 个相同因数乘积的运算,叫做乘方。
    • 好!我们来举个例子比如1+2=3 1×2=2 32=9
  • “现在你都学会了么?”
  • “蒽!”sc回答道,“这怎么能难倒tgopknight?”
  • 骑士大爷得意的笑了一笑,现在你应该就会捉这道题了:
  • 已知 a+b+c=n,a2+b2+c2=m,a3+b3+c3=k ,求解 a,b,c
  • 这可难倒了聪明的sc,她立刻给tgopknight去看,tgopknight虽然是丰之崎学园的学神,但是高端科学家唐沟铺骑士的题岂能简简单单的秒掉。她想到了机智聪明的学OI的你一定可以解决

输入格式

  • 四个整数 n,m,k,p
  • 其中 n,m,k 如上文所述, p 为输出格式的参数

输出格式

  • 由于a,b,c可能有多组解,且实数具有一定的精度误差。本题采取了特殊的处理方式。
  • 选手仅需要输出 ap+bp+cp 可以保证其值唯一确定。输出采取A/B的形式,其中 (A,B)=1 ,若答案为 0 请输出0/1

数据范围

  • Subtask1: 10 分,测试点数1: n=6,m=14,k=36,1p10
  • Subtask2: 10 分,测试点数1: n=1,m=2,k=3,1p10
  • Subtask3: 30 分,测试点数5: p=40n,m,k10
  • Subtask4: 50 分,测试点数10:对于前5个测试点满足: 0n,m,k,p15
  • 对于后五个测试点满足: 0n,m,k200p10

分析 DP + 数学

  • f[i]=ai+bi+ci ,则
    f[i]=(a+b+c)f[i1](ab+bc+ac)f[i2]+abcf[i3](i>3)
    (可以自己试着配一下)
  • 考虑转移方程中的三个参数
    • a+b+c=n
    • ab+bc+ac=(a+b+c)2(a2+b2+c2)2=n2m2
    • (a2+b2+c2)(a+b+c)=nm
      a3+b3+c3+(a+b+c)(ab+bc+ac)3abc=nm
      k+nn2m23abc=nm
      abc=k+nn2m2nm3=2k+n33nm6
  • 则转移方程就变为
    f[i]=nf[i1]n2m2f[i2]+2k+n33nm6f[i3](i>3)
  • 因为要输出分数,我们用两个数组记录 f[i] 的分子和分母模拟分数运算, 两个数组都要开 long_long 并且每求出一次都要约分

代码

#include <iostream>
#include <cstdio>

using namespace std;

typedef long long ll;
int n, m, k, P;
ll g[15], f[15];

inline ll gcd(ll x, ll y)
{
    ll r = x % y;
    while (r) x = y, y = r, r = x % y;
    return y;
}

int main()
{
    freopen("math.in", "r", stdin);
    freopen("math.out", "w", stdout);

    scanf("%d%d%d%d", &n, &m, &k, &P);
    f[1] = n; f[2] = m; f[3] = k; g[1] = g[2] = g[3] = 1;
    const ll p = n * n - m, 
             q = 2 * k + n * n * n - 3 * m * n;
    for (int i = 4; i <= P; ++i)
    {
        ll ax = n * f[i - 1], ay = g[i - 1];
        ll bx = p * f[i - 2], by = 2 * g[i - 2];
        ll cx = q * f[i - 3], cy = 6 * g[i - 3];

        g[i] = ay * by / gcd(ay, by);
        g[i] = g[i] * cy / gcd(g[i], cy);
        f[i] = ax * g[i] / ay - bx * g[i] / by + cx * g[i] / cy;

        ll tmp = gcd(f[i], g[i]);
        f[i] /= tmp; g[i] /= tmp;
    }
    if (g[P] < 0 && f[P] > 0) 
        g[P] = -g[P], f[P] = -f[P];
    cout << f[P] << "/" << g[P] << endl; 

    fclose(stdin); fclose(stdout);
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值