[2020HDU多校第七场][HDU 6847][D. Decision]

赛后听说题解是环套树上倍增表示一脸懵逼...又是被学弟们爆踩的一天_(:з」∠)_

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6847

题目大意:\(a,c,m,t\)为给定常数,\(V_1,V_2\)为从区间\([0,t]\)内等概率生成的两个整数,令\(X_0=V_1+V_2\),\( X_{n+1}=aX_n+c \mod m\),求\(X_{|V_1-V_2|}\)为偶数的概率

题解:将题目转换为枚举\(V_1,V_2\)的所有取值,求\(X_{|V_1-V_2|}\)为偶数的方案数。考虑令\(f_0=V_1+V_2, f_{n+1}=af_n+c\),即数列不取模时的值。可以通过高中学过的数列知识计算得出\(f_n+\frac{c}{a-1}=a^n(f_0+\frac{c}{a-1})\),移项得到\(f_n =a^nf_0+c\cdot \frac{a^n-1}{a-1}=a^nf_0+c\sum_{i=0}^{n-1}a^i\)

   枚举\(|V_1-V_2|\)的值\(d\),要求的就是\(X_d = f_d \bmod m\)为偶数的方案数。令\(p_n=a^n, s_n=\sum_{i=0}^{n-1}a^i\),则\(X_d \equiv (V_1+V_2)p_d + cs_d \mod m\)。由于此时\(d\)已经固定,所以式子中的\(p_d\)与\(cs_d\)可以看作两个常数\(c_1,c_2\),同时我们不妨设\(V_1 \ge V_2\),则有\(V_1=V_2+d,X_d \equiv (V_2+d+V_2)c_1 + c_2 \mod m\),化简得到\(X_d \equiv 2c_1V_2 + c_1d+c_2 \mod m\),是一个\(kx+b\)的形式。

   现在问题就转化成了,已知整数\(x \in [0,t-d]\)(\(V_1=x+d\)要在\([0,t]\)内),求\(kx+b \bmod m\)为偶数的方案数。注意到我们之前求出的\(k=2c_1\)是一个偶数,所以在不考虑取模的情况下,\(kx+b\)的奇偶性是确定的。也就是说,如果\(m\)为偶数,\(kx+b \bmod m\)的奇偶性也是确定的,故我们只需要考虑\(m\)为奇数的情况。

   当\(m\)为奇数时,可以通过观察发现,若一个整数\(y\)对\(2m\)取模的值在\([m,2m-1]\)范围内,即\(\lfloor \frac{y}{m}\rfloor\)为奇数,则\(y \bmod m\)与\(y\)的奇偶性恰好相反,故我们只需要计算出\(kx+b \bmod m\)与\(kx+b\)的奇偶性相反的次数即可。由于当\(\lfloor \frac{kx+b}{m}\rfloor\)为奇数时满足这个条件,相当于我们只要求\(\lfloor \frac{kx+b}{m}\rfloor \bmod 2 = 1\)的次数,即\(x\)取遍\([0,t-d]\)时\(\lfloor \frac{kx+b}{m}\rfloor \bmod 2\)的和。而\(a \bmod b = a-\lfloor \frac{a}{b} \rfloor b\),所以我们要求的就是\(\sum_{x=0}^{t-d} \lfloor \frac{kx+b}{m}\rfloor -2\lfloor \frac{kx+b}{2m}\rfloor\)。发现减号前后的两个式子都是\(\sum_{i=0}^{n} \lfloor \frac{ai+b}{c} \rfloor \)的形式,故可以使用类欧几里得算法求解,总时间复杂度为\(O(t \log t)\)。

 

#include<bits/stdc++.h>
using namespace std;
#define N 1000010
#define LL long long
int T,t,a,c,m,p[N],s[N];
LL f(LL a,LL b,LL c,LL n)
{
    LL m=(a*n+b)/c;
    if(!a || !m)return 0;
    if(a>=c || b>=c)return n*(n+1)/2*(a/c)+(b/c)*(n+1)+f(a%c,b%c,c,n);
    return n*m-f(c,c-b-1,a,m-1);
}
void init()
{
    scanf("%d%d%d%d",&t,&a,&c,&m);
    p[0]=1;
    for(int i=1;i<N;i++){
        p[i]=1ll*p[i-1]*a%m;
        s[i]=(s[i-1]+p[i-1])%m;
    }
    LL x=0,y=1ll*(t+1)*(t+1);
    for(int d=0;d<=t;d++){
        int res=0,k=2ll*p[d],b=(1ll*c*s[d]+1ll*d*p[d])%m;
        if(m&1)res=f(k,b,m,t-d)-2ll*f(k,b,2*m,t-d);
        if(b&1)res=t-d+1-res;
        if(d)res*=2;
        x+=res;
    }
    x=y-x;
    LL d=__gcd(x,y);
    x/=d,y/=d;
    printf("%lld/%lld\n",x,y);
}
int main()
{
    scanf("%d",&T);
    while(T--)init();
}
View Code

由于一开始做这题的时候把题目要求的奇偶看反了,所以代码看上去可能有些奇怪_(:з」∠)_

值得注意的是在求\(k\)的值时不能对\(m\)取模,否则可能会导致\(k\)为奇数进而性质失效

posted @ 2020-08-11 18:43  DeaphetS  阅读(553)  评论(0编辑  收藏  举报