[HDU-6847] Decision (2020多校7T4)
阿新 • • 發佈:2020-08-11
[HDU-6847] Decision (2020多校7T4)
列舉\(|v_1-v_2|\)後,可以遞推,用含首項(\(v_1+v_2\))的一次函式表示函式值為\(a(v_1+v_2)+b\),則問題等價於求
\(\begin{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)-(m\mod 2)\cdot \lfloor \frac{ai+b}{m}\rfloor )\mod 2\)
這個式子即把每次被\(m\)取模減少的\(m\)算進貢獻
可以看到操作非常簡單,可以直接套上萬能歐幾里得的板子
當然,也可以對於\(m\)的各種情況討論,轉化為求\(\lfloor \frac{ai+b}{m}\rfloor\),其主要思想還有應用 \(x\mod 2=x-2\cdot \lfloor \frac{x}{2}\rfloor\) 的轉化
我比賽時去抄了自己的類歐幾里得模板
#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\n",ans/g,tmp/g); } }