f(a,b,c,n)=∑ni=0⌊ai+bc⌋
给定a,b,c,n,求f(a,b,c,n)
扩展:
g(a,b,c,n)=∑ni=0i⌊ai+bc⌋
h(a,b,c,n)=∑ni=0⌊ai+bc⌋2
首先从最简单的f开始推导。
f(a,b,c,n)=∑ni=0⌊ai+bc⌋
当a≥c或b≥c时
其实就相当于把上式的分数变成 ⌊aic+bc⌋ ,然后两个变成真分数。得到:
f(a,b,c,n)=f(a % c,b % c,c,n)+n(n+1)2⌊ac⌋+(n+1)⌊bc⌋
当a < c且b < c时
令 m=⌊an+bc⌋ ,上式可以表示为:
f(a,b,c,n)=∑ni=0∑mj=1[⌊ai+bc⌋≥j]
这个可以理解为一条直线在横坐标为0——n的整数时,越过第一象限的点数量。
继续推:
f(a,b,c,n)=∑ni=0∑m−1j=0[⌊ai+bc⌋≥j+1]
把分数去掉
f(a,b,c,n)=∑ni=0∑m−1j=0[ai≥jc+c−b]
f(a,b,c,n)=∑ni=0∑m−1j=0[ai>jc+c−b−1]
两边除掉a
f(a,b,c,n)=∑ni=0∑m−1j=0[i>jc+c−b−1a]
左边只有i,这样就舒服多了。下一步:
f(a,b,c,n)=∑m−1j=0(n−⌊jc+c−b−1a⌋)
观察到括号里面是一个等差数列和一个f形式的求和,得到:
f(a,b,c,n)=nm−f(c,c−b−1,a,m−1)
可以发现,第1、3个系数从(a,c)变成(c,a%c)。所以就叫它类欧几里得。
边界条件:a=0
g(a,b,c,n)=∑ni=0i⌊ai+bc⌋
首先依然是考虑a≥c或b≥c的情况。因为抽出来有一个平方和,所以得到:
g(a,b,c,n)=g(a % c,b % c,c,n)+n(n+1)(2n+1)6⌊ac⌋+n(n+1)2⌊bc⌋
当a < c且b < c时,根据f的思路,可以得到:
g(a,b,c,n)=∑ni=0i∑mj=1[⌊ai+bc⌋≥j]
g(a,b,c,n)=∑ni=0i∑m−1j=0[i>jc+c−b−1a]
对于任意一个j,为了使表达式为真,i至少为 ⌊jc+c−b−1a⌋+1 ,又因为上限为n,可以得到一个等差数列,所以:
g(a,b,c,n)=∑m−1j=0(n−⌊jc+c−b−1a⌋)(n+⌊jc+c−b−1a⌋+1)2
拆开来得到:
g(a,b,c,n)=12∑m−1j=0(n(n+1)−⌊jc+c−b−1a⌋−⌊jc+c−b−1a⌋2)
最终得到:
g(a,b,c,n)=mn(n+1)−f(c,c−b−1,a,m−1)−h(c,c−b−1,a,m−1)2
式子还和h有关,所以还要推h
h(a,b,c,n)=∑ni=0⌊ai+bc⌋2
当a≥c或b≥c,拆开来得到:
h(a,b,c,n)=h(a % c,b % c,c,n)+n(n+1)(2n+1)6⌊ac⌋2+(n+1)⌊bc⌋2+2⌊bc⌋f(a % c,b % c,c,n)+2⌊ac⌋g(a % c,b % c,c,n)+⌊ac⌋⌊bc⌋n(n+1)
当a < c且b < c时
为了方便,要把 n2 拆一下,得到: n2=2∗n(n+1)2−n=2∑ni=0i−n
可以得到:
h(a,b,c,n)=∑ni=02∑ai+bcj=1j−ai+bc
把两部分分开,得到:
h(a,b,c,n)=2∑m−1j=0(j+1)∑ni=0[⌊ai+bc⌋≥j+1]−f(a,b,c,n)
中间的按照上面的思路推吧,最终得到:
h(a,b,c,n)=m(m+1)n−2g(c,c−b−1,a,m−1)−2f(c,c−b−1,a,m−1)−f(a,b,c,n)
#include
#include
#include
#include
using namespace std;
const int mo=1e9+7,inv2=500000004,inv6=166666668;
typedef long long LL;
int a,b,c,l,r;
struct data
{
int f,g,h;
};
data calc(int a,int b,int c,LL n)
{
data tmp;
if (!a)
{
tmp.f=tmp.g=tmp.h=0;
return tmp;
}
if (a>=c || b>=c)
{
tmp=calc(a%c,b%c,c,n);
n%=mo;
tmp.h=(tmp.h+n*(n+1)%mo*(2*n+1)%mo*inv6%mo*(a/c)%mo*(a/c)%mo
+(n+1)*(b/c)%mo*(b/c)%mo
+(LL)2*(a/c)*tmp.g%mo
+(LL)2*(b/c)*tmp.f%mo
+n*(n+1)%mo*(a/c)%mo*(b/c))%mo;
tmp.f=(tmp.f+n*(n+1)/2%mo*(a/c)+(n+1)*(b/c))%mo;
tmp.g=(tmp.g+n*(n+1)%mo*(2*n+1)%mo*inv6%mo*(a/c)+n*(n+1)/2%mo*(b/c))%mo;
return tmp;
}
LL m=((LL)a*n+b)/c;
data nxt=calc(c,c-b-1,a,m-1);
n%=mo; m%=mo;
tmp.f=((n*m-nxt.f)%mo+mo)%mo;
tmp.g=(LL)((n*(n+1)%mo*m-nxt.f-nxt.h)%mo+mo)*inv2%mo;
tmp.h=((m*(m+1)%mo*n-(LL)2*(nxt.g+nxt.f)%mo-tmp.f)%mo+mo)%mo;
return tmp;
}
int main()
{
freopen("task.in","r",stdin); freopen("task.out","w",stdout);
scanf("%d%d%d%d%d",&a,&c,&b,&l,&r);
printf("%d\n",(calc(a,b,c,r).g-calc(a,b,c,l-1).g+mo)%mo);
return 0;
}