[HDU-6847] Decision (2020多校7T4) (类欧几里得问题)
枚举(|v_1-v_2|)后,可以递推,用含首项((v_1+v_2))的一次函数表示函数值为(a(v_1+v_2)+b),则问题等价于求
(egin{aligned} sum_{i=0}^n [2|(ai+b)mod m] end{aligned}) ,其中 (n) 对于每个 (v_1-v_2) 是不同的
这个问题,可以转化为一个简单的类欧几里得问题
((ai+b)mod m mod 2= ((ai+b)-(mmod 2)cdot lfloor frac{ai+b}{m} floor )mod 2)
这个式子即把每次被(m)取模减少的(m)算进贡献
可以看到操作非常简单,可以直接套上万能欧几里得的板子
当然,也可以对于(m)的各种情况讨论,转化为求(lfloor frac{ai+b}{m} floor),其主要思想还有应用 (xmod 2=x-2cdot lfloor frac{x}{2} floor) 的转化
我比赛时去抄了自己的类欧几里得模板
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define rep(i,a,b) for(int i=a,i##end=b;i<=i##end;++i)
#define drep(i,a,b) for(int i=a,i##end=b;i>=i##end;--i)
char IO;
template <class T=int> T rd(){
T s=0; int f=0;
while(!isdigit(IO=getchar())) if(IO=='-') f=1;
do s=(s<<1)+(s<<3)+(IO^'0');
while(isdigit(IO=getchar()));
return f?-s:s;
}
const int N=1e6+10;
int t,a,c,m;
int fx[N],fy[N];
ll gcd(ll a,ll b){ return b==0?a:gcd(b,a%b); }
ll D2(ll n){
return n*(n+1)/2;
}
ll F(ll a,ll b,ll c,ll n){
if(n<0) return 0;
if(a==0) return (b/c)*(n+1);
if(a>=c || b>=c) {
ll ans=F(a%c,b%c,c,n)+D2(n)*(a/c)+(n+1)*(b/c);
return ans;
}
ll t=(a*n+b)/c;
ll ans=t*n-F(c,-b+c-1,a,t-1);
return ans;
}
ll CalcMod(int a,int b,int m,int n){
return F(a,b,m,n)-F(a,b,m*2,n)*2;
}
ll Calc(int a,int b,int n){
// for i= [l,r] (ax+b) %m %2
if(~m&1){
// (ax+b)%2;
a%=2,b%=2;
if(a==0) return b*(n+1);
return (n+1+b)/2;
} else {
// (ax+b) %m %2 = ((ax+b)/m + ax+b)%2
int c=a%2,d=b%2;
if(c==0) {
// =((ax+b)/m+b)%2;
if(d==0) return CalcMod(a,b,m,n);
else return (n+1)-CalcMod(a,b,m,n);
} else {
// (ax+b) %m %2 = ((ax+b)/m + (x&1)+d)%2
ll ans=0;
// i%2 == 0
ll t=CalcMod(a*2,b,m,n/2);
if(d) t=n/2+1-t;
ans+=t;
b+=a;
// i%2 == 1
n--;
if(n<0) return ans;
t=CalcMod(a*2,b,m,n/2);
if(!d) t=n/2+1-t;
ans+=t;
return ans;
}
}
}
int main(){
rep(kase,1,rd()) {
t=rd(),a=rd(),c=rd(),m=rd();
fx[0]=1,fy[0]=0;
rep(i,1,t) fx[i]=1ll*fx[i-1]*a%m,fy[i]=(1ll*fy[i-1]*a+c)%m;
ll ans=0;
rep(i,0,t) {
if(i==0) {
ans+=Calc(fx[i]*2%m,fy[i],t);
} else {
// a<b, b - a = i
// a=[0,m-i]
// b=[i,m]
ll tmp=(1ll*i*fx[i]+fy[i])%m;
ans+=Calc(fx[i]*2%m,tmp,t-i)*2;
}
}
ll tmp=1ll*(t+1)*(t+1);
ans=tmp-ans;
ll g=gcd(tmp,ans);
printf("%lld/%lld
",ans/g,tmp/g);
}
}