P5170 [模板] 类欧几里得算法

传送门

关于 f 

f(a,b,c,n)=f(a\%c,b\%c,c,n)+\frac{n*(n+1)}{2}*\left \lfloor \frac{a}{c} \right \rfloor + (n+1)*\left \lfloor \frac{b}{c} \right \rfloor     ( a >= c | b >= c)

f(a,b, c,n)=n*\left \lfloor \frac{an+b}{c} \right \rfloor - f(c,c-b-1,a,\left \lfloor \frac{an+b}{c} \right \rfloor-1) (a < c & b < c)

关于 g

首先有 \left \lfloor \frac{ai+b}{c} \right \rfloor^2=(\left \lfloor \frac{(a\%c)i+(b\%c)}{c} \right \rfloor+\left \lfloor \frac{a}{c} \right \rfloor*i+\left \lfloor \frac{b}{c} \right \rfloor)^2

暴力拆开发现

\small g(a,b,c,n)=g(a\%c,b\%c,c,n)+\frac{n*(n+1)*(2n+1)}{6}*\left \lfloor \frac{a}{c} \right \rfloor^2+(n+1)\left \lfloor \frac{b}{c} \right \rfloor^2+\left \lfloor \frac{a}{c} \right \rfloor\left \lfloor \frac{b}{c} \right \rfloor*n*(n+1)+2\left \lfloor \frac{b}{c} \right \rfloor f(a\%c,b\%c,c,n)+2\left \lfloor \frac{a}{c} \right \rfloor h(a\%c,b\%c,c,n)

但 a < c 的时候有点头凸

考虑   \small x^2=-x + 2*\sum_{i=1}^x i

类似套路的可以推到

\small g(a,b,c,n)=2*\sum_{j=0}^{\left \lfloor \frac{a*n+b}{c} \right \rfloor}(j+1)(n-\left \lfloor \frac{cj-b+c-1}{a} \right \rfloor)=\left \lfloor \frac{a*n+b}{c} \right \rfloor*(\left \lfloor \frac{a*n+b}{c} \right \rfloor+1)-2*h(c, c-b-1, a, \left \lfloor \frac{a*n+b}{c} \right \rfloor-1)-2*f(c, c-b-1, a, \left \lfloor \frac{a*n+b}{c} \right \rfloor-1) - f(a,b,c,n)

关于 h 

跟 f 一样,不想打了


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int Mod = 998244353, inv2 = (Mod+1)/2, inv6 = (Mod+1)/6;
ll mul(ll a, ll b){ return a * b % Mod;}
ll add(ll a, ll b){ return (a + b) >= Mod ? a + b - Mod : a + b; }
ll n, a, b, c; int T; 
struct Node{ ll f, g, h;};
Node Solve(ll a, ll b, ll c, ll n){
	if(c == 0) return (Node){0, 0, 0};
	if(a >= c || b >= c){
		Node tmp = Solve(a % c, b % c, c, n);
		ll f = add(add(mul(mul(a/c, n), mul(n+1, inv2)), mul(b/c, n+1)), tmp.f);
		ll g = mul(mul(a/c, a/c), mul(mul(inv6, n), mul(n+1, n*2+1)));
		g = add(g, mul(mul(b/c, b/c), n+1));
		g = add(g, mul(mul(a/c, b/c), mul(n, n+1)));
		g = add(g, mul(mul(2, a/c), tmp.h));
		g = add(g, mul(mul(2, b/c), tmp.f));
		g = add(g, tmp.g);
		ll h = mul(mul(a/c, n), mul(mul(n+1, n*2+1), inv6));
		h = add(h, mul(mul(b/c, n), (mul(n+1, inv2))));
		h = add(h, tmp.h);
		return (Node){f, g, h};
	}
	ll fn = (a * n + b) / c;
	Node tmp = Solve(c, c - b - 1, a, fn - 1);
	ll f = add(mul(n, fn), Mod - tmp.f);
	ll g = mul(mul(n, fn), fn+1);
	g = add(g, Mod - mul(2, add(tmp.h, tmp.f)));
	g = add(g, Mod - f);
	ll h = mul(n, mul(n+1, fn));
	h = add(h, Mod - add(tmp.f, tmp.g)); h = mul(h, inv2);
	return (Node){f, g, h};
}
int main(){
	scanf("%d", &T);
	while(T--){
		scanf("%lld%lld%lld%lld", &n, &a, &b, &c);
		Node ans = Solve(a, b, c, n);
		cout << ans.f << " " << ans.g <<" " << ans.h << "\n";
	} return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

FSYo

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

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

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

打赏作者

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

抵扣说明:

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

余额充值